1.前言
有了前面的
router
铺垫 接下来学习会更easy
2. vuex简单使用 + 分析
vuex安装
index.js
mutations: { add(state){ state.count++ } }, actions: { add({commit}){ setTimeout(() => { commit("add") }, 1000); } },
思考上面的 参数state 上下文 commit怎么来的
App.vue
<p @click="$store.commit('add')">{{$store.state.count}}</p> <p @click="$store.dispatch('add')">asy:{{$store.state.count}}</p>
3.基本结构
复制store目录 命名我们自己的 zstore
main.js修改引用
// import store from './store' import store from './zstore'
创建我们自己的 zvuex.js
zstore/index.js修改引用
import Vuex from './zvuex'
4. 需求分析
1 实现Store类
1.维持一个响应式状态 state
2.实现commit
3.实现 dispatch
4.getters
2 挂载 $store
5. 基础结构
需要导出一个 store
因为new Vuex.Store({}) 使用的时候 有Store
class Store{ constructor(options){} commit(){} dispatch(){} } function install(_Vue,options){} export default {Store,install}
6. 注册 $store
参考
$router
的写法主要是混入
Vue.mixin({ beforeCreate() { if (this.$options.store) { Vue.prototype.$store = this.$options.store } } })
7. 保存数据信息
关键是这个数据是 响应式的
Vue.util.defineReactive(this,'state',{})
这次我们借力 ,使用 Vue 来创建响应式数据
class Store{ constructor(options){ console.log(" options:",options); console.log(" this:",this); // 保存数据 this.$options = options // Vue.util.defineReactive(this,'state',{}) this.state = new Vue({ data(){ return options.state } }) } commit(){} dispatch(){} }
options
就是挂载上去的 store信息也就是 state mutations
this.state的数据就是响应式的 用到这个数据的组件就会随着这个组件的变化而更新
8. 界面查看效果
点击也生效了
9. 不是标准写法
因为用户可以直接操纵 state了 ,需要通过
commit
核心是我们不希望用户简单轻松的就访问到数据,而且轻易的修改了这个数据,这样会破坏数据流,也不方便追踪数据变化
class Store { constructor(options) { // 保存数据 this.$options = options // Vue.util.defineReactive(this,'state',{}) // 用户访问 name 并且轻松修改了 这不是我们想看到的 // this._vm.name ="修改了" this._vm = new Vue({ data() { return { // 不做代理 $$state:options.state, // name:"yzs" } } }) } get state(){ // 这里的访问就比较深了 ,就是不想用户简单的就访问了我们的数据 return this._vm._data.$$state } set state(z){ console.error("请使用 replaceState 重置state"); } commit() { } dispatch() { } }
10. commit
参考 commit的用法 想象它的实现方式
用法 store.commit("add",2)
payload
载荷 简单理解为参数,其实也就是对接受者有用的数据
commit(type,payload) { //根据type 从用户配置的 mutaions中 获取函数 const entry = this._mutations[type] if(!entry){ return console.error("unknow mutaion") } entry(this.state,payload) }
11. dispatch
比葫芦画瓢 应该能写出来
dispatch(type,payload) { const entry = this._actions[type] if(!entry){ return console.error("unknow actions") } // dispatch 的上下文是 state实例 entry(this,payload) }
注意 这个 dispatch的参数
通常我们在使用时候 称呼为
ctx
上下文 ,那到底是啥呢常规写法
actions: { add(ctx){ setTimeout(() => { ctx.commit("add") }, 1000); } },
结构写法
actions: { add({commit,state,mutations,modules}){ setTimeout(() => { commit("add") }, 1000); } },
dispatch
的上下文 就是这个store
实例对象
12.还是看效果吧
点击异步修改的时候报错
13. this解决方案
这里借用
react
的一种解决方案就是在 构造函数里绑定 函数的作用域
this.commit = this.commit.bind(this) this.dispatch = this.dispatch.bind(this)
自己可以尝试还有哪些解决方案
14.完美的效果,忍不住录个屏吧
15. 附上完整的 zvuex.js
let Vue class Store { constructor(options) { console.log(" options:",options); console.log(" this:",this); // 保存数据 // this.$options = options this._mutations = options.mutations this._actions = options.actions // Vue.util.defineReactive(this,'state',{}) // 用户访问 name 并且轻松修改了 这不是我们想看到的 // this._vm.name ="修改了" this._vm = new Vue({ data() { return { // 不做代理 $$state:options.state, // name:"yzs" } } }) // react的做法 // 绑定 this this.commit = this.commit.bind(this) this.dispatch = this.dispatch.bind(this) } get state(){ // 这里的访问就比较深了 ,就是不想用户简单的就访问了我们的数据 return this._vm._data.$$state } set state(z){ console.error("请使用 replaceState 重置state"); } // 用法 store.commit("add",2) commit(type,payload) { //根据type 从用户配置的 mutaions中 获取函数 const entry = this._mutations[type] if(!entry){ return console.error("unknow mutaion") } entry(this.state,payload) } dispatch(type,payload) { const entry = this._actions[type] if(!entry){ return console.error("unknow actions") } // dispatch 的上下文是 state实例 entry(this,payload) } } function install(_Vue, options) { Vue = _Vue Vue.mixin({ beforeCreate() { if (this.$options.store) { Vue.prototype.$store = this.$options.store } } }) } export default { Store, install }