到目前为止,咱们已经实现了vuex
中的getters
,mutations
,接下来就该轮到咱们的actions
了。
在具体实现actions
以前,咱们必须明确actions
的功能和用途.javascript
详情能够参考vuex-actionshtml
经过官网的介绍,咱们总结得出,在actions
中,咱们主要作两件事,一件是commit mutaions
,另外一件是dispatch other actions
vue
为了可以完成以上两件任务,咱们必须使得在actions
中可以访问到store
中的commit
和dispatch
方法。java
store
中这步操做和getters/mutations
中彻底同样,有须要注意的地方在代码中给出了注释vuex
import Vue from 'Vue'
class Store{
constructor(options){
this._vm = new Vue({
data:options.state
})
...//getters
...// mutations
// actions
let actions = options.actions || {}
this.actions = {}
Object.keys(actions).forEach((key)=>{
this.actions[key] = (payload) =>{
actions[key](this,payload) // 在这里传入this使为了让咱们可以访问到commit和dispatch方法
}
})
get state(){
return this._vm
}
// 在这里,咱们实现一个dispatch方法
dispatch(actionType,payload){
this.actions[actionType](payload)
}
commit(mutationType,payload){
this.mutations[mutationType](payload)
}
}
复制代码
接下来,让咱们注册一个简单的actions
,ide
const store = new Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment ({commit,dispatch}) {
commit('increment')
}
},
getters:{
getCount(state){
return state.count
}
}
})
复制代码
如今咱们注意一下,actions
中的increment
的执行流程函数
// options中的actions绑定到了store实例上
// actions['increment'](this) //执行
// {commit,dispatch} = this // 结构赋值
// commit('increment')
// this.mutations['increment'] 这里会出现问题,this此时并非指`store`实例,而是指向undefined
复制代码
this
指向类的方法内部若是含有this
,它默认指向类的实例。可是,必须很是当心,一旦单独使用该方法,极可能报错。测试
class Logger {
printName(name = 'there') {
this.print(`Hello ${name}`);
}
print(text) {
console.log(text);
}
}
const logger = new Logger();
const { printName } = logger;
printName(); // TypeError: Cannot read property 'print' of undefined
复制代码
上面代码中,printName
方法中的this
,默认指向Logger
类的实例。可是,若是将这个方法提取出来单独使用,this
会指向该方法运行时所在的环境(因为 class
内部是严格模式,因此 this
实际指向的是undefined
),从而致使找不到print
方法而报错。ui
一个比较简单的解决方法是,在构造方法中绑定this
,这样就不会找不到print
方法了。this
class Logger {
constructor() {
this.printName = this.printName.bind(this);
}
// ...
}
复制代码
另外一种解决方法是使用箭头函数。
class Obj {
constructor() {
this.getThis = () => this;
}
}
const myObj = new Obj();
myObj.getThis() === myObj // true
复制代码
箭头函数内部的this
老是指向定义时所在的对象。上面代码中,箭头函数位于构造函数内部,它的定义生效的时候,是在构造函数执行的时候。这时,箭头函数所在的运行环境,确定是实例对象,因此this
会老是指向实例对象。
所以咱们必须想办法保障this
是指向store
实例的
在这里,咱们将commit,dispatch
声明为箭头函数,由于箭头函数中的this
在创造时就被肯定了,而不会随着上下文环境而发生变化。
dispatch = (actionType,payload) =>{
this.actions[actionType](payload)
}
commit = (mutationType,payload) =>{
this.mutations[mutationType](payload)
}
复制代码
此时完整代码为
class Store {
constructor(options) {
this.data = options.state;
let getters = options.getters || {}
this.getters = {}
// mutations
let mutations = options.mutations || {}
this.mutations = {}
Object.keys(mutations).forEach((key) => {
this.mutations[key] = (payload) => {
mutations[key](this.state, payload)
}
})
// 把getter对象上的属性所有绑定到this.getter上
Object.keys(getters).forEach((key) => {
Object.defineProperty(this.getters, key, {
get: () => getters[key](this.state)
})
})
let actions = options.actions || {}
this.actions = {}
Object.keys(actions).forEach((key) => {
this.actions[key] = (payload) => {
actions[key](this, payload) // 在这里传入this使为了让咱们可以访问到commit和dispatch方法
}
})
}
get state() {
return this.data
}
dispatch = (actionType, payload) => {
this.actions[actionType](payload)
}
commit = (mutationType, payload) => {
this.mutations[mutationType](payload)
}
}
复制代码
经过上面的代码,咱们发如今实现getters
,mutations
,actions
的绑定时,逻辑都是同样的,咱们能够将其抽取出来,封装成一个函数。
let forEach = (obj,callback)=>{
Object.key(obj).forEach(key=>{
callback(key,obj[key])
})
}
复制代码
使用封装函数,修改咱们的代码:
let forEach = (obj,callback)=>{
Object.key(obj).forEach(key=>{
callback(key,obj[key])
})
}
class Store {
constructor(options) {
this.data = options.state;
let getters = options.getters || {}
this.getters = {}
// mutations
let mutations = options.mutations || {}
this.mutations = {}
forEach(getters,(key,fn)=>{
Object.defineProperty(this.getter,key)=>{
get:()=>{
return fn(this.state)
}
}
})
forEach(mutations,(key,fn)=>{
this.mutations[key] = (payload)=>{
fn((this.state, payload))
}
})
let actions = options.actions || {}
this.actions = {}
forEach(actions,(key,val)=>{
this.actions[key] = (payload)=>{
fn(this,payload)
}
})
}
get state() {
return this.data
}
dispatch = (actionType, payload) => {
this.actions[actionType](payload)
}
commit = (mutationType, payload) => {
this.mutations[mutationType](payload)
}
}
复制代码
测试是否成功
store.dispatch('increment')
console.log(store.getters.getCount) // 输出1 符合预期
复制代码
未完待续...