vuex的应用场景,你们可能或多或少知道,用来管理一些全局数据,或者多个页面都会使用到的数据,好比,咱们项目中常见的用户信息,一般使用vuex来管理。html
这里,咱们思考一个问题,如何没有vuex,还有哪些方式能够实现一些公共数据的管理?vue
以上两种方式,虽然能够用来管理咱们的全局数据,可是随着项目愈来愈复杂,全局数据愈来愈多,目前这样的管理方式成本仍是有些高,因此,咱们须要一套系统化的,流程化的机制来管理全局数据,而vuex就是为此而诞生的。vuex
vuex的优势:它不只仅是一个全局数据的管理器,同时它最大的特性是支持响应式的,也就是说使用vuex管理的数据若是发生改变,那么引入这些数据的组件都会自动刷新,vue-cli
首先,咱们经过上图要明白如下几点:npm
以上基本覆盖了vuex的经常使用知识点,接下来,咱们来经过一个具体的代码案例来深刻理解一下。后端
咱们来实现一个简单的计数器,点击能够增长数字, 首先,本次代码都在基于vue-cli3生成的项目模版去实现的。api
第一步:安装vuex缓存
npm i vuex --save
复制代码
第二步:引入vuexbash
//main.js
import App from './App.vue'
Vue.config.productionTip = false
//vuex的使用
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
//全部的数据都存放在state中
state: {
count: 0
},
//mutations实现同步操做
mutations: {
increment (state, params) {
state.count += params;
}
},
//actions中实现一些异步操做
actions: {
increment ({state}, params) {
setTimeout(() => {
state.count += params;
}, 3000)
}
},
getters: {
doubleCount (state) {
return state.count * 2;
}
}
});
new Vue({
store,
render: h => h(App),
}).$mount('#app')
复制代码
//app.vue
<template>
<div id="app">
<span>count: {{count}}</span>
<button @click="addCount1">count++</button>
<br>
<span>doubleCount: {{doubleCount}}</span>
<button @click="addCount2">count++</button>
</div>
</template>
<script>
export default {
name: 'app',
computed: {
count () {
return this.$store.state.count;
},
doubleCount () {
return this.$store.getters.doubleCount;
}
},
methods: {
addCount1 () {
this.$store.commit('increment', 2); //mutations经过commit触发
},
addCount2 () {
this.$store.dispatch('increment', 2); //actions经过dispatchc触发
}
}
}
</script>
复制代码
经过上面的代码,咱们要清楚如下几点:app
也就是说:咱们一般能够经过state和getters来获取全局数据,也能够经过mutations和actions修改全局数据,mutations是同步操做,actions是异步操做。
import Vuex from 'vuex';
const store = new Vuex.Store({
state: {},
mutations: {}
...
});
复制代码
new Vue({
store,
render: h => h(App),
}).$mount('#app')
复制代码
问题:
经过上面的学习,咱们知道了,全部状态变量都是定义在store中的state属性中,那么,如何获取state中的数据呢? //第一种方式:
export default {
computed: {
count () {
return this.$store.state.count;
},
doubleCount () {
return this.$store.getters.doubleCount;
},
number () {
return this.$store.state.number;
}
},
}
即直接在computed计算属性中返回所需数据,缺点就是:若是状态树愈来愈多,每一个属性都须要咱们在computed中声明而且返回一次,不太友好,解决方案就是mapState
复制代码
//第二种方式:
import {mapState} from 'vuex';
export default {
computed: mapState([
'count',
'doubleCount',
'number'
]),
}
同时,若是想自定义别名,也能够给mapState传入一个对象,自定义处理,可是上面的写法,咱们就没法在computed声明当前vue实例下本身的计算属性了,解决方案就是rest运算符...
复制代码
//第三种方式:
import {mapState} from 'vuex';
export default {
computed: {
...mapState([
'count',
'number'
]),
...mapGetters([
'doubleCount'
]),
//也能够自定义其余计算属性
},
}
复制代码
经过上面,咱们知道了能够有不少种不一样的写法去读取state里面的数据,getters也相似,上面第三种方式也有体现,咱们须要知道各类写法的优缺点,同时,在实际项目中,咱们只须要采用最优写法便可,即第三种方式。
Getter与State的做用都是定义一些全局使用的数据,Getter和State的关系就相似于computed和data的关系,Getter的返回值会被缓存起来,只有它所依赖的state中的数据发生变化才会跟着从新计算。
咱们只须要明白Getter的做用以及与State的区别便可,写法和State相似,参考上面便可。
上面咱们知道了,能够经过state和getter来定义和读取状态,那么接下来,如何修改状态呢?记住一句话:更改 Vuex 的 store 中的状态的惟一方法是提交 mutation.
首先,要说明一下mutation中的几个概念:
咱们在具体的代码中说明:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
//increment就是在mutation中定义的事件类型
increment (state, payload) {
state.count += payload.amount
}
}
})
store.commit('increment', {
amount: 10 // commit中传的参数就是载荷
})
复制代码
接下来,咱们要说一下在组件中mutation的几种写法: //第一种
export default {
methods: {
addCount () {
this.$store.commit('increment', 2);
}
}
}
复制代码
//第二种方式:
import {mapMutations} from 'vuex';
export default {
methods: {
...mapMutations([
'increment'
]),
addCount () {
this.increment(2);
}
}
}
复制代码
注意点:在mutation中都是同步事件,由于mutation的做用就是能够捕捉到每一次的提交或者修改记录,若是是异步事件,devtool很难捕捉到,这时就要用到Action了
Action和Mutation都是用来修改状态的,区别就是action中一般是一些异步事件,而且经过dispatch去分发事件,固然,有一点,咱们要知道actions内部也是经过提交mutation去修改数据的。
这里,具体写法就不说了,和mutation相似。
经过上面的讲解,咱们都知道了,修改state的惟一路径就是 提交mutation,固然,若是咱们直接修改了state里面的值,在非严格模式下,也是能够生效的,可是不建议这么作,在严格模式下,vue会直接报错
还有一点:表单里使用v-model双向绑定的若是是state里面的数据,这时,若是在严格模式下,会直接报错的,由于数据修改完,v-model内部就默认直接修改了state里面的数据,具体解决方案,能够直接参考官网:vuex.vuejs.org/zh/guide/fo…
vuex其实自己内容是比较简单的,可是因为咱们引入mapState,mapGetter等map写法以后,可能会容易产生混淆,致使感受vuex相关概念较多,没法真正理清,这里咱们在总结一下:
首先vuex的核心就是store,也叫仓库,他就是一个容器,里面包含着state,getter,mutation,action等属性,
- 首先这些状态都定义在哪里呢?
即直接定义在state中就能够啦
- 定义完之后,怎么在组件中读取状态呢?
经过this.store.getter的方式去读取,固然为了写法更加间接,咱们引入了mapState和mapGetter。
- 定义完之后,怎么在组件中修改状态呢?
vuex只支持一种方式:那就是commit mutation,action内部自己也是commit mutaition, 固然,依然是为了写法间接,咱们又引入了mapMutations和mapActions。
经过上面的总结,咱们知道了map系列api,都只是为了如何更简洁的读取和修改状态,暂时抛开这一部分,咱们发现,其实vuex的内容其实很简单。
这一节,咱们主要看一下vuex的实现原理,同时,实现也能够简易版的vuex。
经过上面的介绍,咱们知道了vuex中的状态state和单纯的全局对象仍是不一样的,主要体如今:
那,咱们接下来看看vuex具体是如何实现响应式的?其实内部就是经过vue的响应式机制去实现的。
下面,咱们能够手动实现一个简易版的vuex
import Vue from 'vue'
const Store = function Store (options = {}) {
const {state = {}, mutations={}} = options
this._vm = new Vue({
data: {
$$state: state
},
})
this._mutations = mutations
}
Store.prototype.commit = function(type, payload){
if(this._mutations[type]) {
this._mutations[type](this.state, payload)
}
}
Object.defineProperties(Store.prototype, {
state: {
get: function(){
return this._vm._data.$$state
}
}
});
export default {Store}
复制代码
经过上面的代码,咱们看到,其实vuex内部也是经过new Vue()的方式,将state存储在vue实例的data中,从而实现响应式的。