通过vuex进行父子组件之间的通讯

今天与大家分享vuex进行父子组件之间的通讯

1.什么是vuex?

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

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

目录介绍

 

vuex介绍:不管组件在树的何种位置,任何组件都能获取到状态和触发行为。可以将其想象为一个“前端数据库”(数据仓库),让其在各个页面上实现数据的共享包括状态,并且可操作;核心就是 解决组件间的通讯问题

2.vuex实现

进入项目目录:

npm install vuex -S

 直接安装可能遇到版本冲突 可能需要自定义版本号 

 

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

 store创建index.js配置各大模块

//导入vue模块
import Vue from 'vue'
​
//导入vuex模块,如果不知道名字可在package.json中查看
import Vuex from 'vuex'
​
//在vue中作用vuex
Vue.use(Vuex)
​
//导入相关模块
import state from '@/store/state'
import actions from '@/store/actions'
import getters from '@/store/getters'
import mutations from '@/store/mutations'
​
//创建store实例,并注册模块
//注意与导入的名字相同。
const store = new Vuex.Store({
  state,
  actions,
  getters,
  mutations
})
​
//最后导出模块
export default store

2.5 在main.js中导入vuex 

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

import Vue from 'vue'
import App from './App'
import router from './router'

import ElementUI from 'element-ui'

//导入store模块
import store from '@/store'

import 'element-ui/lib/theme-chalk/index.css'

import axios from '@/api/http'
import VueAxios from 'vue-axios'
Vue.use(VueAxios,axios)

Vue.use(ElementUI)

process.env.MOCK && require('@/mock')

Vue.config.productionTip = false

window.vm = new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

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

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

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

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

export default state

3.2 设置全局参数 

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

1) mutations.js

//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

      //转换折叠图标的状态
      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

/*
 * 通过计算属性读取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属性

<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

//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方式。

/*
 * 通过计算属性读取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组件

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

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

4. 异步处理

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

var x = true;
while(x);
console.log("don't carry out"); //不会执行

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

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

setTimeout(function(){
    console.log("async task .... ");
}, 3000);

4.1 异步修改参数 

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

1) 在store中声明一个参数

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

export default state

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

//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中定义获取参数的方法

//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添加异步设置参数功能

/*
 * 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用于演示异步设置操作

<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,加入准备好的后台接口。

//VUEX 异步请求后台数据
'VUE_ASYN_REQ':'/userMsg/vueAsynAction!asynAction.action',

5.3 store/actions.js

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

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组件中,加入异步获取后台数据的方法。

<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>

vuex状态持久化 

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

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

1) 安装

npm install vuex-persist -S

  

 指定版本号

npm install vuex-persist@3.1.3 -S

2)导入及配置: 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值