同样,这一次我们只讲原理,如果你还不会Vuex的使用,简易移步官网
任务分析
先来根据Vuex的流程图来看一下我们需要做什么
- vuex也是一个插件
- 实现四个东西:state/mutations/actions/getters
- 创建Store
- 数据响应式
插件
关于插件这里同样不多说,不会的请移步官网,这里依旧贴一张图
在安装插件时,通过Vue.use触发插件的install方法
function install(_Vue) {
Vue = _Vue
Vue.mixin({
beforeCreate() {
// 只有根元素才有store
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
这里注意只有第一次调用时才给元素添加store,也就是根节点
四个核心
首先要有一个可实例化的Store类,这点官网给的实例可以看出来
那我们就先创建一个Store类,它接收一个配置对象
class Store {
constructor(options) {
this.state = new Vue({
data() {
return { ...options.state}
}
})
this.mutations = options.mutations
this.actions = options.actions
options.getters && this.handleGetters(options.getters)
}
}
state负责存储数据,借用Vue实例来实现响应式;mutations用来存储改变state的方法;actions用来存储异步方法,这里注意actions本身并不具备异步特性,仅作为异步方法的容器,他可以调用mutations中的方法;getters可以用来读取state的内容,将结果处理返回
class Store {
constructor(options) {
this.state = new Vue({
data() {
return { ...options.state}
}
})
this.mutations = options.mutations
this.actions = options.actions
options.getters && this.handleGetters(options.getters)
}
commit = (type, args) => {
this.mutations[type](this.state, args)
}
dispatch = (type, args) => {
this.actions[type]({
commit: this.commit,
state: this.state
}, args)
}
handleGetters(getters) {
this.getters = {}
Object.keys(getters).forEach(key => {
Object.defineProperty(this.getters, key, {
get: () => {
return getters[key](this.state)
}
})
})
}
}
测试
现在我们已经实现了一个简易版的Vuex,我们接下来进行一下测试
新建一个store.js,用来实例化store
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state) {
state.count++
}
},
actions: {
addAsync({ commit }) {
setTimeout(() => {
commit('add')
}, 1000)
}
},
getters: {
getCount(state) {
return state.count
}
}
})
在main.js中引入store
import store from './store'
new Vue({
store,
router,
render: h => h(App),
}).$mount('#app')
编写Vue组件,调用Vuex方法
<div>
{{$store.getters.getCount}}
<br />
<button @click="$store.commit('add')">同步+1</button>
<button @click="$store.dispatch('addAsync')">延时+1</button>
</div>
测试结果如下