最近在看了vuex源码相关实现,这里只是简单实现一下state,getters,mutations,actions,不带module的,完整的实现可以在github查看。github.com/Xaw-xu/vuex
入口文件 index.js
import {Store,install} from './store'
export {
Store,install//install 为组件的安装方法,Vue.use()进行安装
}
export default {
Store,install
}
// 以两种方式导出,可以以不同的方式引入
store.js
export let _Vue; // 这里用来存储Vue
export class Store {
}
// 我们在每个组件中都可以以this.$store拿到数据,核心就是用mixin在组件生命周期中进行混入,每一个组件都会挂载一个$store
export const install = (Vue) => {
_Vue = Vue; // Vue.use()会执行插件的install方法,将Vue传入进来,这里存一下,在store类中会用到
Vue.mixin({
beforeCreate() {
// 我们使用的时候会在根实例中传入一个store
// new Vue({
// router,
// store,
// render: (h) => h(App),
// }).$mount("#app");
if (this.$options.store) {// 在根组件中可以用this.$options.store拿到store
this.$store = this.$options.store;
} else {
// 对于子组件直接去取父级的store进行挂载,最后所有的组件中都可以访问到store
if (this.$parent && this.$parent.$store) {
this.$store = this.$parent.$store;
}
}
},
});
};
state 实现
export class Store {
constructor(options) {
//这里的options.state 即为用户new Vuex.Store({state:{}})时传入的state
//Vuex数据修改后视图可以更新实际上内部就是new了一个vue实例
//Vue中定义数据,属性名如果是$开头,数据是不会被代理到实例上的,也就是通过this._vm.$$state取值是取不到的
this._vm = new _Vue({
data() {
return {
$$state: options.state,//$标识表示内部的状态
};
},
});
}
get state() {
//可以通过_data访问到
return this._vm._data.$$state;
}
}
getters实现
工具函数
export const forEach = (obj = {}, fn) => {
Object.keys(obj).forEach((key) => fn(obj[key], key));
};
export class Store {
constructor(options) {
//getters是有缓存的,内部其实是用computed实现
this.getters = {};
const getters = options.getters; //用户传过来的geters,写的是方法,取值的时候是属性
const computed = {};
forEach(getters, (fn, key) => {
computed[key] = () => {
// 依赖值不变就不会更新
return fn(this.state);
};
Object.defineProperty(this.getters, key, {
get: () => this._vm[key],// 这里用计算属性包装一层,否则就没有缓存的效果
});
});
//这里的options.state 即为用户new Vuex.Store({state:{}})时传入的state
//Vuex数据修改后视图可以更新实际上内部就是new了一个vue实例
//Vue中定义数据,属性名如果是$开头,数据是不会被代理到实例上的,也就是通过this._vm.$$state取值是取不到的
this._vm = new _Vue({
data() {
return {
$$state: options.state,//$标识表示内部的状态
};
},
computed,
});
}
get state() {
//可以通过_data访问到
return this._vm._data.$$state;
}
}
mutations 实现
export class Store {
constructor(options) {
//getters是有缓存的,内部其实是用computed实现
this.getters = {};
const getters = options.getters; //用户传过来的geters,写的是方法,取值的时候是属性
const computed = {};
forEach(getters, (fn, key) => {
computed[key] = () => {
// 依赖值不变就不会更新
return fn(this.state);
};
Object.defineProperty(this.getters, key, {
get: () => this._vm[key],// 这里用计算属性包装一层,否则就没有缓存的效果
});
});
//这里的options.state 即为用户new Vuex.Store({state:{}})时传入的state
//Vuex数据修改后视图可以更新实际上内部就是new了一个vue实例
//Vue中定义数据,属性名如果是$开头,数据是不会被代理到实例上的,也就是通过this._vm.$$state取值是取不到的
this._vm = new _Vue({
data() {
return {
$$state: options.state,//$标识表示内部的状态
};
},
computed,
});
// mutations
this._mutations = {};
//这里为上面提到的工具函数
forEach(options.mutations, (fn, key) => {
this._mutations[key] = (payload) => fn.call(this, this.state, payload);
});
}
// 这里使用箭头函数,保证解构后this指向
commit = (type, payload) => {
this._mutations[type](payload);
};
get state() {
//可以通过_data访问到
return this._vm._data.$$state;
}
}
actions 实现同mutations
export class Store {
constructor(options) {
//getters是有缓存的,内部其实是用computed实现
this.getters = {};
const getters = options.getters; //用户传过来的geters,写的是方法,取值的时候是属性
const computed = {};
forEach(getters, (fn, key) => {
computed[key] = () => {
// 依赖值不变就不会更新
return fn(this.state);
};
Object.defineProperty(this.getters, key, {
get: () => this._vm[key],// 这里用计算属性包装一层,否则就没有缓存的效果
});
});
//这里的options.state 即为用户new Vuex.Store({state:{}})时传入的state
//Vuex数据修改后视图可以更新实际上内部就是new了一个vue实例
//Vue中定义数据,属性名如果是$开头,数据是不会被代理到实例上的,也就是通过this._vm.$$state取值是取不到的
this._vm = new _Vue({
data() {
return {
$$state: options.state,//$标识表示内部的状态
};
},
computed,
});
// mutations
this._mutations = {};
//这里为上面提到的工具函数
forEach(options.mutations, (fn, key) => {
this._mutations[key] = (payload) => fn.call(this, this.state, payload);
});
this._actions = {};
forEach(options.actions, (fn, key) => {
this._actions[key] = (payload) => fn.call(this, this, payload);
});
}
// 这里使用箭头函数,保证解构后this指向
commit = (type, payload) => {
this._mutations[type](payload);
};
dispatch = (type, payload) => {
this._actions[type](payload)
};
get state() {
//可以通过_data访问到
return this._vm._data.$$state;
}
}
以上就基本实现了一个简易版的vuex。