第一阶段:实现全局数据管理
vuex入口文件暴露install方法和Store类,Vue.use默认会执行install方法并传递Vue的构造
let Vue;
let install = (_vue) => {
console.log(_vue);
Vue = _vue;
}
class Store {
}
export default {
install,Store
}
install中使用mixin执行beforeCreate钩子,这样就可以在每个组件中执行一段逻辑
let install = (_vue) => {
console.log(_vue);
Vue = _vue;
Vue.mixin({
beforeCreate(){
}
})
}
逻辑如下:判断是否为根组件,即$options(用户传递vue的对象)上有无store
- 是,则挂载$store属性为store
- 否,挂载store为父级的store属性
Vue.mixin({
beforeCreate(){
if(this.$options && this.$options.store) {
this.$store = this.$options.store
}else {
this.$store = this.$parent && this.$parent.$store
}
}
})
第二阶段:实现数据劫持,vuex数据改变也会触发视图更新
new Vue然后将state挂载到data
class Store {
constructor(options){
let state = options.state;
this._vm = new Vue({
data: {
state: state
}
})
}
get state(){
return this._vm.state
}
}
第三阶段:实现getters
初始化时为每个getter定义defineProerty,取值时执行其对应函数,将函数返回值返回
## vuex.js
if(options.getters){
let getters = options.getters;
forEach(getters, (getterName, getterFn) => {
Object.defineProperty(this.getters,getterName,{
get:()=>{
return getterFn(state);
}
})
})
}
借用vue中的computed,将getter定义在vm上;
## vuex.js
const computed = {}
this._vm = new Vue({
data: {
state: state
},
### computed挂载到vue上
computed
})
if(options.getters){
let getters = options.getters;
forEach(getters, (getterName, getterFn) => {
### 将getter挂载到computed上
computed[getterName] = () => {
return getterFn(this.state);
}
Object.defineProperty(this.getters,getterName,{
get:()=>{
### 取值时直接从vm实例上获取 这样才能实现依赖收集
return this._vm[getterName]
}
})
})
}
function forEach(obj,callback){
Object.keys(obj).forEach(item=>callback(item,obj[item]));
}
第四阶段:实现更改数据流程
store类上定义commit、dispatch方法,分别执行store上的mutation、action
## vuex.js
constructor(){
if (options.mutations) {
let mutations = options.mutations;
forEach(mutations, (mutationName, mutationFn) => {
this.mutations[mutationName] =()=> mutationFn.call(this,state);
})
}
if (options.actions) {
let actions = options.actions;
forEach(actions, (actionName, actionFn) => {
this.actions[actionName] =()=> actionFn.call(this,this);
})
}
}
commit(type){
console.log(this);
this.mutations[type]()
}
dispatch(type){
this.actions[type]()
}
考虑原型链,在构造中再次定义commit、dispatch方法,内部以call执行原型上的commit/dispatch绑定this
let {commit,dispatch} = this;
this.commit = (type) => {
commit.call(this,type)
}
this.dispatch = (type) => {
dispatch.call(this,type)
}
至此,我们完成了初版的vuex
完整代码如下
let Vue;
let install = (_vue) => {
console.log(_vue);
Vue = _vue;
Vue.mixin({
beforeCreate(){
if(this.$options && this.$options.store) {
this.$store = this.$options.store
}else {
this.$store = this.$parent && this.$parent.$store
}
}
})
}
class Store {
constructor(options){
let state = options.state;
this.getters = {};
this.mutations = {};
this.actions = {};
const computed = {}
this._vm = new Vue({
data: {
state: state
},
computed
})
if(options.getters){
let getters = options.getters;
forEach(getters, (getterName, getterFn) => {
computed[getterName] = () => {
return getterFn(this.state);
}
Object.defineProperty(this.getters,getterName,{
get:()=>{
return getterFn(state);
}
})
})
}
if (options.mutations) {
let mutations = options.mutations;
forEach(mutations, (mutationName, mutationFn) => {
this.mutations[mutationName] =()=> mutationFn.call(this,state);
})
}
if (options.actions) {
let actions = options.actions;
forEach(actions, (actionName, actionFn) => {
this.actions[actionName] =()=> actionFn.call(this,this);
})
}
let {commit,dispatch} = this;
this.commit = (type) => {
commit.call(this,type)
}
this.dispatch = (type) => {
dispatch.call(this,type)
}
}
get state(){
return this._vm.state
}
commit(type){
console.log(this);
this.mutations[type]()
}
dispatch(type){
this.actions[type]()
}
}
function forEach(obj,callback){
Object.keys(obj).forEach(item=>callback(item,obj[item]));
}
export default {
install,Store
}