vue全家桶(vuex简版源码的实现)

Vuex

Vuex 集中式存储管理应⽤的所有组件的状态,并以相应的规则保证状态以可预测的⽅式发⽣变化。
下面是Vuex工作的流程图
在这里插入图片描述

安装: vue add vuex

vue add vuex

核⼼概念
  • State 状态,数据
  • Actions 异步操作
  • Mutations 更改状态的函数
  • store 包含以上概念的容器
状态 -state

state用来存储状态

export default new Vuex.Store({
  state: { 
    count: 0 
  },
})
状态变更 - mutations

mutations⽤于修改状态,store.js

mutations: {
  add(state) {
    state.count++
  }
}
派⽣状态 - getters

从state派⽣出新状态,类似计算属性

export default new Vuex.Store({
	getters: {
	   doubleCounter(state) { // 计算剩余数量
		  return state.count * 2;
	   }
    }
})
动作 - actions

添加业务逻辑,类似于controller(副作用操作)

export default new Vuex.Store({
  actions: {
	add({ commit }) {
	  setTimeout(() => {
	    commit('add')
	  }, 1000);
	}
  }
})

测试的代码

<p @click="$store.commit('add')">conunt: {{$store.state.count}}</p>
<p @click="$store.dispatch('add')">async conunt: {{$store.state.count}}</p>

vuex原理解析

分析
  • 实现⼀个插件:声明Store类,挂载$store
  • Store具体实现:
    • 创建响应式的state,保存mutations、actions和getters
    • 实现commit根据⽤户传⼊type执⾏对应mutation
    • 实现dispatch根据⽤户传⼊type执⾏对应action,同时传递上下⽂
    • 实现getters,按照getters定义对state做派⽣
  • 挂载$store
初始化:Store声明、install实现,kvuex.js

创建一个kvue.js文件

// 实现一个插件
let _Vue
class Store {
  constructor(options) {
    // 需要保存一下 mutations以及actions
    this._mutations = options.mutations
    this._actions = options.actions

    // 创建响应式的state
    this._vm = new _Vue({
      // 借助vue 的响应式
      data () {
        // data 这个对象中个key最终都会被代理到vue这个实例中去
        return {
          // 不希望被代理,就加上$
          $$state: options.state
        }
      }
    })
  }
  // 暴露给外界的方法,让用户可以访问
  get state () {
    return this._vm._data.$$state
  }
  set state (v) {
    // 不允许对state直接做替换, 所有的操作都是可控的
    console.error('please use replaceState to reset state')
  }
}

function install(Vue) {
  _Vue = Vue
  // 混入
  Vue.mixin({
    beforeCreate() {
      // 判断是否有store选项
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}

// 导出的对象就是Vuex
export default { Store, install }

为什么要⽤混⼊⽅式写?主要原因是use代码在前,Router实例创建在后,⽽install逻辑⼜需要⽤ 到该实例,这里是一个比较巧妙的方法(主要是为了延迟执行)

实现commit:根据⽤户传⼊type获取并执⾏对应mutation

class Store {
  constructor(options = {}) {
    // 保存⽤户配置的mutations选项
    this._mutations = options.mutations || {}
  }
  commit(type, payload) {
    // 获取type对应的mutation
    const entry = this._mutations[type]
    if (!entry) {
      console.error(`unknown mutation type: ${type}`);
      return
    }
   // 指定上下⽂为Store实例
   // 传递state给mutation
   entry(this.state, payload);
  }
}

实现actions:根据⽤户传⼊type获取并执⾏对应action

class Store {
  constructor(options = {}) {
    // 保存⽤户编写的actions选项
    this._actions = options.actions || {}
    // 绑定commit上下⽂否则action中调⽤commit时可能出问题!!
    // 同时也把action绑了,因为action可以互调
    const store = this
    const {commit, action} = store
    this.commit = function boundCommit(type, payload) {
      commit.call(store, type, payload)
    }
    this.action = function boundAction(type, payload) {
      return action.call(store, type, payload)
    }
 }
dispatch(type, payload) {
  // 获取⽤户编写的type对应的action
  const entry = this._actions[type]
  if (!entry) {
    console.error(`unknown action type: ${type}`);
    return
  }
  // 异步结果处理常常需要返回Promise
  return entry(this, payload);
 }
}

下面附上完整代码

// 实现一个插件
let _Vue
class Store {
  constructor(options = {}) {
    // 需要保存一下 mutations以及actions
    this._mutations = options.mutations
    this._actions = options.actions

    // 创建响应式的state
    this._vm = new _Vue({
      // 借助vue 的响应式
      data () {
        // data 这个对象中个key最终都会被代理到vue这个实例中去
        return {
          // 不希望被代理,就加上$
          $$state: options.state
        }
      }
    })
    
    // 修改this 的指向
    this.commit = this.commit.bind(this)
    this.dispatch = this.dispatch.bind(this)
  }
  // 暴露给外界的方法,让用户可以访问
  get state () {
    return this._vm._data.$$state
  }
  set state (v) {
    // 不允许对state直接做替换, 所有的操作都是可控的
    console.error('please use replaceState to reset state')
  }
  // 实现commit方法
  // 修改state
  // this.$store.commit('add', 1)
  commit (type, payload) {
    // 获取type对应的mutation
    const entry = this._mutations[type]

    if (!entry) {
      // 如果不存在就做一次警告
      console.error('unknown mutation')
      return
    }

    // 传入state作为参数,
    entry(this.state, payload)
  }

  // 实现dispatch方法
  dispatch (type, payload) {
    // 获取type对应的actions
    const entry = this._actions[type]

    if (!entry) {
      // 如果不存在就做一次警告
      console.error('unknown action')
      return
    }

    // 传入Stores实例做参数(上下文),
    return entry(this, payload)
  }
}

function install(Vue) {
  _Vue = Vue
  // 混入
  Vue.mixin({
    beforeCreate() {
      // 判断是否有store选项
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}

// 导出的对象就是Vuex
export default { Store, install }
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值