说说我的理解(不一定对),由于前端的组件化开发常常难免涉及到组件之间的通信。对于一个小型项目来说,通过父子组件通信就够用了。但是,可能随着项目扩大,存在兄弟组件或者祖孙组件通信的通信。其解决方法通常有两种:中央bug机制和间接调用上一级组件(或者上上级组件)。额,难免有些复杂。于是,vuex站出来了。vuex可以便于项目更加方便的处理这些公用数据,大大减轻了公用数据给项目带来的负担。整体上vuex像是把公用数据放在一个吊篮里面,然后那个组件用就使用吊篮里面的公用数据和方法便可。
(1)项目的基础安装
为了方便,这里使用的是vue2的语法结构。首先,需要构建vue2的基本目录结构。
利用vue-cli脚手架工具创建一个基本的vue2结构目录:
//首先,新建一个文件夹用于存放项目目录,说明:开始的时候使用cmd,但是报了一个安全管理错误(脚本无法运行)
//解法:使用管理员权限的powerShell运行如下指令:
set-ExecutionPolicy RemoteSigned
//npm改用淘宝镜像
npm config set registry http://registry.npm.taobao.org
//更新npm工具
npm install -g npm
//安装vue-cli,当时有一个报错如下:
//Vue-cli3 更新 vue create is a Vue CLI 3 only command and you are using Vue CLI 2.9.6.
//说的是:当前vue-cli的版本是2.x的,vue create初始化项目需要使用vue-cli 3.x及以上版本。
//卸载安装失败的vue-cli
npm uninstall -g vue-cli
//安装最新版vue-cli
npm install -g @vue/cli
//检测更新完成
vue --version
//显示当前为4.x表示更新完成
//初始化一个vue2项目
vue create my-vuex
//安装vuex
npm install vuex --save
//到此安装部分结束
(2)在项目中导入vuex
首先在main.js同级目录下构建一个store.js文件,写入如下代码:(只需要了解基本目录,下面有详细总结)
import Vue from 'vue'
import Vuex from 'vuex' //引入Vuex
Vue.use(Vuex) //使用vuex
export default new Vuex.Store({
state:{ //公共数据源都需要放到state里面存储
},
mutations:{ //同步方法处理state里面的数据
},
actions:{ //异步方法处理state里面的数据
},
getters:{ //基于state里面的数据创造的计算通用属性
}
})
修改main.js文件
import Vue from 'vue'
import App from './App.vue'
import store from '/src/store.js' //引入vuex的配置文件
Vue.config.productionTip = false
new Vue({
store, //实例化vue的时候实例化vuex里面的store对象
render: h => h(App),
}).$mount('#app')
下面主要是介绍vuex的四大关键用法,每种用法都涉及到两种写法(map映射和this调用),将分开介绍,至于项目具体使用,采用其中任意一种都行。其次,整体架构方面,store.js用来维护所有组件的公用数据(包括属性和属性对应的操作方法)。
(1)创建方法:
和常用data里面定义变量的方法一样:(定义一个所有组件公用的count变量)
state:{
count:0
},
(2)使用方法:
其一,直接在对应组件里面使用**{{ this.$store.state.count }}**就能访问(这里的this是可以去掉的,因为是在template中)
其二,使用map映射的方式:
<script>
import { mapState } from 'vuex'//引入映射
computed: {//将公用属性写入该组件的computed计算属性里面
...mapState(['count']),//注意加上括号
},
</script>
先说一下怎么用,然后再来解释为什么被理解成存放同步方法。
举个例子需要对count作增加处理:
mutations:{
add(state){
state.count++;
}
},
其一,this调用的方式,需要调用的时候,直接在对应的函数体里面写上:this.$store.commit(“add”);
其二,map映射方式:
import { mapMutations } from 'vuex'
//methods中的使用
methods: {
...mapMutations(['add']),//...其实就是一个语法糖,编译时将里面的函数依次解构出来
addNum() {//正常触发的函数,这里其实就是一个@click="addNum"
this.add()
},
},
带参函数,有些时候可能需要给函数添加额外参数,做如下调整便可:
//store.js
mutations:{
add(state,step){
state.count+=step;
}
},
//组件methods
methods:{
addNum() {
this.add(100)//100就对应函数里面的step参数
//另:this.$store.commit('add',100);
},
}
解释为什么必须是同步函数:
在Vue.js devtools插件中可以找到原因,异步函数在处理state里面的数据时,devtool是检测不到变化的,换言之异步函数对于数据的处理很可能导致渲染错误。
和上面的Mutation类似,(这里对于异步操作在devtool工具中是能够检测数据变化的)下面直接给带参函数例子:
actions:{
addAsync(context,step){//context是一个与store实例具有相同方法和属性的对象
setInterval(()=>{
context.commit('add',step);
//注意对于数据的修改异步方法然需要调用已经存在的同步方法
},1000);
},
}
使用方法也和mutation类似,其一: this.$store.dispatch(‘add’,step);
其二,使用方法如下:
//引入mapActions
import { mapActions } from 'vuex'
//组件methods方法中使用
methods: {
...mapActions(['subAsync']),
subNum() {
this.subAsync(50)//等价与上面的step
}
},
类似于计算属性,直接给出例子:
getters:{
showNum(state){
return "返回当前最新数据:【"+state.count+"】"
}
}
调用方法和state里面的属性类似:
其一:{{this.$store.getters.showNum}},
其二,map映射形式:
//引入 mapGetters
import { mapGetters } from 'vuex'
//组件中的使用同样需要放在computed属性中:
computed: {
...mapGetters(['showNum']),
},
plus:注意,虽然使用this的形式能够在任何组件中修改state或者computed里面的数据,但是这种写法是错误的。因为vuex本身就是用来维护公用数据的。这样一写就会导致很难追踪到是那个组件或者那个函数里面修改了数据。因此正确的写法是将任何对于数据的操作都以函数的形式放在store.js中。
感谢黑马教程出的vuex视频教程。