手写vuex核心代码
vuex基本用法
//store/index.js
import Vue from 'vue'
import Vuex from 'Vuex'
Vue.use(Vuex)// 很关键下面会将
let store = {
state: {
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
}
}
export default new Vuex.Store(store)
分析
我们是通过new Vuex.store(option)获得一个store实例,也就是说vuex内部的源码的样子为
Class Store{
constructor(options) { // this.$store
//options为上面的store
}
}
let Vuex = {
Store
}
在vue项目中的使用
也就是说vuex本质上是一个拥有store类作为属性的一个对象,通过new Vuex.Store(store) 来使用,在vue项目中的使用方法为
import Vue from 'vue'
import App from './App.vue'
import store from './store' // store.js文件
Vue.config.productionTip = false
在.vue中使用方法为
{{$store.state.name}}
{{$store.state.age}}
也就是说每一个组件对象this上都会有$store这个属性,那么这个属性怎么来的呢?这就涉及到vue插件的使用了也就是上文store.js文件中的Vue.use(Vuex)//官网解释如下
Vue.use( plugin )
-
参数:
{Object | Function} plugin
-
用法:
安装 Vue.js 插件。如果插件是一个对象,必须提供
install
方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。该方法需要在调用
new Vue()
之前被调用。当 install 方法被同一个插件多次调用,插件将只会被安装一次。
install源码解析
也就是说vuex源码会有一个install方法,
Class Store{
constructor(options) { // this.$store
//options为上面的store
}
}
let Vuex = {
Store
}
export const install = (Vue) => {
// 这里就会让vue的每一个组件对象this都能获取到$store,具体做法如下
Vue.mixin({
beforeCreate(){
// 这里的this是vue的实例, this.$option.store 实际上在vue初识话的时候传入的store,也就是new Vue({store,...})
//const vm = new Vue({
// store,// 将store类的实例也就是export default new Vuex.Store(store)传入到vue的构造函数中
// render: h => h(App)
//}).$mount('#app')
if (this.$options.store) { // 所以能获取到store的为根
// this.$options.store => new Vuex.Store
// this.$store => new Vuex.Store
this.$store = this.$options.store; // 给根属性增加$store属性
} else if (this.$parent && this.$parent.$store) {
this.$store = this.$parent.$store
}
}
})
}
这样每一个组件对象this上都会有store在每个组件的template模板中就可以使用vuex中存储的全局状态了
使用过vuex的都知道,vuex中的属性被修改后页面也会被重新编译,也就是可以达到像vue组件中的data中定义的属性一样,当data中的属性被修改后,template模板也会被重新编译,这就是vue的响应式系统,vuex中的state属性正是借助了vue的响应式系统实现的。所以vuex强依赖vue
vuex核心原理解析
// util方法
const forEachValue = (obj, cb) => {
Object.keys(obj).forEach(key => cb(obj[key], key))
}
export class Store { // vuex 是基于Vue来实现的
constructor(options) { // this.$store
let computed = {}
this.getters = {}
forEachValue(options.getters, (value, key) => {
computed[key] = () => {
return value.call(this, this.state);
}
Object.defineProperty(this.getters, key, {
get: () => {
return this._vm[key];
}
})
}) // getters 函数 和 “属性” 取值
this._vm = new Vue({
data: {
// // 内部会使用代理 把所有开头不为$的属性代理给this._vm
$$state: options.state
},
computed
});
this.mutations = {};
this.actions = {}
forEachValue(options.mutations, (fn, key) => {
this.mutations[key] = (payload) => fn.call(this, this.state, payload)
});
forEachValue(options.actions, (fn, key) => {
this.actions[key] = (payload) => fn.call(this, this, payload)
})
}
// 属性访问器
get state() {
return this._vm._data.$$state
}
// 当用户调用this.$store.commit 方法的时候会调用这个方法
commit = (type, payload) => {
this.mutations[type](payload)
}
dispatch = (type, payload) => {
this.actions[type](payload)
}
}
至此vuex的基本原理和源码分析完毕