vue11Vuex解说+子父传参详细使用

2022-11-18 21:25:25 浏览数 (1)

目录

1. vue组件间通讯

1.1 父子组件

1.2 消息总线

1.3 vuex

2. vuex使用

2.1 简介

2.2 安装

2.3 创建store模块

2.4 创建vuex的store实例并注册上面引入的各大模块

2.5 在main.js中导入vuex

3. 将折叠和展开效果使用vuex实现

3.1 在state.js中声明全局参数

3.2 设置全局参数

3.3 Main.vue组件

3.3.1 直接通过state获取状态值

3.3.2 getter方式获取store中的值

3.4 LeftAside.vue组件

4. 异步处理

4.1 异步修改参数

5. 异步调用后台方法

6. Vuex的常用辅助函数

7. vuex的模块化

8. vuex状态持久化


1. vue组件间通讯

1.1 父子组件

  • 父组件-->子组件,通过子组件的自定义属性:props
  • 子组件-->父组件,通过自定义事件:this.$emit('事件名',参数1,参数2,...);

1.2 消息总线

这种方式需要另外创建一个vue实例,用来当做消息总线

1.3 vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。可以想象为一个“前端数据库”(数据仓库), 让其在各个页面上实现数据的共享包括状态,并且可操作。

Vuex分成五个部分: 1.State:单一状态树 2.Getters:状态获取 3.Mutations:触发同步事件 4.Actions:提交mutation,可以包含异步操作 5.Module:将vuex进行分模块

2. vuex使用

2.1 简介

Vuex是专门为vue应用程序开发的状态管理模式,将组件的共享状态抽取出来,以一个全局单例模式进行管理,组件树构成一个巨大的视图,不管组件在树的何种位置,任何组件都能获取到状态和触发行为。可以将其想象为一个“前端数据库”(数据仓库),让其在各个页面上实现数据的共享包括状态,并且可操作。(核心就是 解决组件间的通讯问题)

2.2 安装

进入项目目录:

代码语言:javascript复制
npm install vuex -S

2.3 创建store模块

创建store目录及需要的文件:

2.4 创建vuex的store实例并注册上面引入的各大模块

勘误: new Vuex({}),修改为 new Vuex.Store({})

2.5 在main.js中导入vuex

main.js是vue应用程序的入口,在这个文件中导入vuex组件。

 通过在根实例中注册store选项,该store实例会注入到根组件下的所有子组件中,且子组件可以通过this.$store访问到。

3. 将折叠和展开效果使用vuex实现

3.1 在state.js中声明全局参数

state.js的作用可以看作是存放全局参数的容器,组件可以通过state.js获取全局参数。

代码语言:javascript复制
//存放全局参数的容器,组件可以通过state.js获取全局参数
const state = {
  LeftAsideState: 'open'
}

export default state

3.2 设置全局参数

当在TopNav.vue中点击展开或折叠时,需要将当前的状态设置到全局参数中,以便于其他组件可以获取到状态。 mutations:相当于setter方法,处理数据的唯一途径,state的改变或赋值只能在这里。

1) mutations.js

代码语言:javascript复制
//Mutation 必须是同步函数。原因:异步方法,我们不知道什么时候状态会发生改变,所以也就无法追踪了
//如果我们需要异步操作,Mutations就不能满足我们需求了,这时候我们就需要Actions了
const mutations = {

  //state,即state.js中定义的state,借此可以访问state中定义的全局变量
  //payload: 载荷,保存传递参数的容器
  setLeftAsideState: (state, payload) => {
    //通过载荷为全局参数赋值,相当于setter
    state.LeftAsideState = payload.LeftAsideState;
  }

}

export default mutations

2)如何调用mutations.js中定义的setLeftAsideState为全局参数赋值? 见一下示例:

当点击TopNav.vue组件中的折叠或展开按键时,需要将当前的状态设置到全局参数中,以便于其他组件可以获取到状态。

TopNav.vue

代码语言:javascript复制
 //转换折叠图标的状态
      doToggle: function() {
        //如果原来为打开状态则点击后转换为折叠
        //如果原来为折叠状态则点击后转换为打开
        this.opened = !this.opened;

        //通过自定义事件将状态值传递个父组件,及Main.vue
        //相应的Main.vue组件中需要设置‘left-open-collapsed’
        //使用vuex方式后,将原来的实现方式注释
        //this.$emit("left-open-collapsed",this.opened);

        /*
         * 通过vuex进行组件间的通讯,当点击折叠或展开时设置全局参数,以便于
         * 其他组件获取状态。
         *
         *  第一种提交方式:
         * this.$store.commit(type, payload);
         * 参数type: 与mutations.js定义的方法名一致
         * 参数payload:载荷,是个json对象,其中的参数与state.js中定义的全局参数名一致
         * 该方法的作用是为全局参数LeftAsideState赋值。
         * 
         * 第二种提交方式:
         * this.$store.commit({type: 'setLeftAsideState', LeftAsideState: 'open'});
         * 即:将type参数与要设置的全局参数放在一个json对象中。
         */
        this.$store.commit("setLeftAsideState", {
          LeftAsideState : this.opened ? 'open' : 'collapsed'
        });
        
      }

3.3 Main.vue组件

Main.vue组件获取设置的全局变量(LeftAsideState)的值,并需要根据变量的值来改变自身的状态。 state中存放的状态值是响应式的,从store实例中读取状态最简单的方式是在计算属性中返回某个状态。

3.3.1 直接通过state获取状态值

Main.vue

代码语言:javascript复制
/*
 * 通过计算属性读取store中的值,并根据获取到的值返回展开或折叠样式。
 * 定义好计算属性后,通过绑定的方式使用
 * <el-aside :>
 */
computed: {
  leftAsideClass: function() {
    //可以通过以下的方式进行获取,但是不推荐。
    let tmp = this.$store.state.LeftAsideState;
    return tmp == 'open' ? "main-aside" : "main-aside-collapsed";
  }
}

不推荐使用this.$store.state.LeftAsideState;获取状态值,后续使用getter方式获取。

template部分 使用计算属性设置el-aside的class属性

代码语言:javascript复制
<template>
  <el-container class="main-container">
    <!-- 侧边栏有折叠效果,通过class控制折叠还是显示的效果 -->
    <!--leftAsideClass 为定义的计算属性 -->
    <el-aside :class="leftAsideClass">
      <!-- 原来使用父子组件传参方式,修改为vuex方式实现 -->
      <!-- <LeftAside :opened="opened"></LeftAside> -->
      <LeftAside></LeftAside>
    </el-aside>
    <el-container>
      <el-header class="main-header">
        <!-- 原来使用父子组件传参方式,修改为vuex方式实现 -->
        <!-- <TopNav @left-open-collapsed="toggleLeftStat"></TopNav> -->
        <TopNav></TopNav>
      </el-header>
      <el-main class="main-center">
        <router-view></router-view>
      </el-main>
    </el-container>
  </el-container>
</template>

启动服务,查看运行效果。

3.3.2 getter方式获取store中的值

编辑/store/getters.js

代码语言:javascript复制
//getters将state中定义的值暴露在this.$store.getters对象中
//可以通过如下代码访问:this.$store.getters.getLeftAsideState
const getters = {

  //参数state即为stroe中存放的state,在state.js定义
  getLeftAsideState: function(state) {
    return state.LeftAsideState;
  }

}

export default getters

将Main.vue组件中访问store中数据的方式修改为getters方式。

代码语言:javascript复制
/*
 * 通过计算属性读取store中的值,并根据获取到的值返回展开或折叠样式。
 */
computed: {
  leftAsideClass: function() {
    //可以通过以下的方式进行获取,但是不推荐。
    //let tmp = this.$store.state.LeftAsideState;

    //getters方式获取状态值
    let tmp = this.$store.getters.getLeftAsideState;
    return tmp == 'open' ? "main-aside" : "main-aside-collapsed";
  }
}

3.4 LeftAside.vue组件

代码语言:javascript复制
 computed: {
      //通过计算属性获取定义在store中的状态值,并根据状态值来设定返回值,用于标记左侧栏展开或折叠的状态
      //因为命名冲突,可将上面再data中定义的同名属性删除.
      isCollapse: function() {
        return this.$store.getters.getLeftAsideState == 'open' ? false : true;
      }
    }

至此,展开或折叠效果使用vuex方式修改完毕。运行项目查看运行效果。

4. 异步处理

同步 同步模式,即上述所说的单线程模式,一次只能执行一个任务,函数调用后需等到函数执行结束, 返回执行的结果,才能进行下一个任务。如果这个任务执行的时间较长,就会导致「线程阻塞」

代码语言:javascript复制
var x = true;
while(x);
console.log("don't carry out"); //不会执行

异步 异步模式,即与同步模式相反,可以一起执行多个任务,函数调用后不会立即返回执行的结果, 如果任务A需要等待,可先执行任务B,等到任务A结果返回后再继续回调。 异步常见的使用场景是后台耗时的任务。

js中最常见的异步是定时器

代码语言:javascript复制
setTimeout(function(){
    console.log("async task .... ");
}, 3000);

4.1 异步修改参数

现做一个异步修改参数值的简单示例:

1) 在store中声明一个参数

代码语言:javascript复制
//存放全局参数的容器,组件可以通过state.js获取全局参数
const state = {
  LeftAsideState: 'open',
  
  //声明一个存放人员名称的参数,设置默认值,用于演示异步修改参数
  PersonName:'张飞'
}

export default state

2) 在mutations.js中定义修改参数的方法:

代码语言:javascript复制
//Mutation 必须是同步函数。为什么呢?异步方法,我们不知道什么时候状态会发生改变,所以也就无法追踪了
//如果我们需要异步操作,Mutations就不能满足我们需求了,这时候我们就需要Actions了
const mutations = {

  //state,即state.js中定义的state,借此可以访问state中定义的全局变量
  //payload: 载荷,保存传递参数的容器
  setLeftAsideState: (state, payload) => {
    //通过载荷为全局参数赋值,相当于setter
    state.LeftAsideState = payload.LeftAsideState;
  },

  //设置人员名称,用于演示异步
  setPersonName: (state, payload) => {
    state.PersonName = payload.PersonName;
  }

}

export default mutations

3)在getters.js中定义获取参数的方法

代码语言:javascript复制
//getters将state中定义的值暴露在this.$store.getters对象中
//可以通过如下代码访问:this.$store.getters.getLeftAsideState
const getters = {

  //参数state即为stroe中存放的state,在state.js定义
  getLeftAsideState: function(state) {
    return state.LeftAsideState;
  },

  //定义获取人员名称的方法
  getPersonName: function(state) {
    return state.PersonName;
  }

}

export default getters

4) 编辑actions.js添加异步设置参数功能

代码语言:javascript复制
/*
 * Action与mutation定义语法类型,不同点:
 * 1) Action提交的是mutation,而不是直接变更状态,mutation直接变更状态
 * 2) Action可以包含任意异步操作
 * 3) Action的回调函数接收一个 context 上下文参数
 * 详见方法内的注释
 */
const actions = {

  /*
   * context为上下文参数,与 store 实例有着相同的方法和属性
   * context参数包含:state、rootState、getters、mutations、actions 五个属性
   * payload为负载,是一个存放需要传递的参数的容器,和mutations的含义一致
   */
  setPersonNameAsyn: function(context, payload) {
    
    //异步操作,第一个参数为一个匿名函数,第二参数为延迟的时间,单位为毫秒。
    //作用:在3秒或调用第一个参数定义的匿名函数。
    setTimeout(function() {
      
      //action提交的是mutation,而不能直接变更状态
      //第一个参数setPersonName即为mutation中定义的方法名
      //payload即为参数容器。
      //通过context的commit方法提交一个mutation,由mutation负责
      //修改参数,action负责提供异步功能,(mutation必须是同步的)
      context.commit('setPersonName', payload);
    }, 3000);
  }

}

export default actions

5) 编辑Home.vue用于演示异步设置操作

代码语言:javascript复制
<template>
  <div>
    <h1>首页</h1>
    <p>
      {{personName}}
    </p>
    <p>
      <button @click="setPersonName">异步设置人员名称</button>
    </p>
  </div>
</template>

<script>
  export default {
    name: 'Home',
    data: function() {
      return {

      }
    },
    computed: {
      personName: function() {
        return this.$store.getters.getPersonName;
      }
    },
    methods: {
      setPersonName: function() {
        //调用定义在actions中的方法,调用方式如下:
        //this.$store.dispatch(type,payload);
        //第一个参数type: 定义在actions中的方法名
        //第二个参数payload:负载(一个json对象),即要传递的参数
        this.$store.dispatch('setPersonNameAsyn', {
          PersonName: '关羽'
        });
      }
    }
  }
</script>

<style>
</style>

现在可以运行程序,体验异步操作。

5. 异步调用后台方法

5.1 准备后台方法

准备一个后台接口,可以让其睡眠几秒钟再返回数据,以模拟耗时的后台处理过程。

5.2 配置api/actions.js

配置api/action.js,加入准备好的后台接口。

代码语言:javascript复制
//VUEX 异步请求后台数据
'VUE_ASYN_REQ':'/userMsg/vueAsynAction!asynAction.action',

5.3 store/actions.js

在store/actions.js中增加发送ajax请求的方法。

代码语言:javascript复制
const actions = {
  
  ......
  
  /*
   * 在actions.js中无法直接获取vue实例的this对象,但需要该对象来获取axios
   * 对象,以便于发送ajax请求,可以通过payload参数由调用者传入vue实例的this
   * 对象。
   */
  getDataFromApiAsyn: function(context, payload) {
    let _this = payload._this;
    let url = _this.axios.urls.VUE_ASYN_REQ;

    _this.axios.post(url, {
      param: payload.PersonName
    }).then(resp => {

      //通过resp响应对象获取返回的数据,并赋予payload
      payload.PersonName = resp.data.data;

      //提交一个mutation,用于设置state中的参数。
      context.commit('setPersonName', payload);
    }).catch(error => {

    })
  }
  
  ......
  
 }

5.4 Home.vue

在Home.vue组件中,加入异步获取后台数据的方法。

代码语言:javascript复制
<template>
  <div>
    <h1>首页</h1>
    <p>
      {{personName}}
    </p>
    <p>
      <button @click="setPersonName">异步设置人员名称</button>
      <button @click="doAjaxReq">异步获取后台数据</button>
    </p>
  </div>
</template>

<script>
  export default {
    name: 'Home',

    data: function() {
      return {

      }
    },

    computed: {
      personName: function() {
        return this.$store.getters.getPersonName;
      }
    },

    methods: {
      setPersonName: function() {
        //调用定义在actions中的方法,调用方式如下:
        //this.$store.dispatch(type,payload);
        //第一个参数type: 定义在actions中的方法名
        //第二个参数payload:负载(一个json对象),即要传递的参数
        this.$store.dispatch('setPersonNameAsyn', {
          PersonName: '关羽'
        });
      },

      doAjaxReq: function() {
        //因为在actions中需要使用vue实例中的this参数,
        //所以在此处将this参数作为负载传入。
        this.$store.dispatch('getDataFromApiAsyn', {
          PersonName: '赵云',
          _this: this
        });
      }
    }
  }
</script>

<style>
</style>

6. Vuex的常用辅助函数

mapState/mapGetters/mapMutations/mapActions

以mapGetters为例:

 7. vuex的模块化

vuex的模块化是为了在大型项目中,更好的管理store中的数据。在大型项目中store中的数据会非常多,直接放在store中容器引发混乱,这时候就需要模块化的管理。

示例: 在store目录中创建一个usermsg目录,在其中创建一个user-msg.js,如下图所示:

 修改store/index.js文件:

在Home.vue组件上测试: 图一:

图二:

还可以使用如下方式获取模块中的值:this.$store.state.userMsg.userName; 但不建议使用。

8. vuex状态持久化

Vuex 解决了多视图之间的数据共享问题。但是运用过程中又带来了一个新的问题是,Vuex 的状态存储并不能持久化。也就是说当你存储在 Vuex 中的 store 里的数据,只要一刷新页面,数据就丢失了。

引入vuex-persist 插件,它就是为 Vuex 持久化存储而生的一个插件。不需要你手动存取 storage ,而是直接将状态保存至 cookie 或者 localStorage 中。

1) 安装

代码语言:javascript复制
npm install vuex-persist -S

2)导入及配置:

 以上就是今天的分享,感谢大家的观赏!!!

0 人点赞