基于Vuex从零实现自己的Vuez插件-getters(二)

569 阅读2分钟

在上篇文章中,我们已经实现了对所有的Vue实例绑定同一个store实例。

回顾Vuex的使用

Vue官网vuex的使用

实现一个Store

  • 通过上面官网的介绍,我们可以知道数据的访问,都是通过store.的方式来进行的,也就是说,store的实例上必须有这些属性,根据这个,我们来设计一个Store类。
  • store.的属性都来自传递进来的参数对象

class Store{
  constructor(options){
    this.data = options.state;
    let getters = options.getters || {}
    this.getters = {}
    // 把getter对象上的属性全部绑定到this.getter上
    Object.keys(getters).forEach((key) => {
      Object.defineProperty(this.getters, key, {
        get: () => getters[key](this.state)
      })
    })
  }
  get state(){
      return this.data
  }
}

也许这段代码,你有些地方看不懂,为什么要这么做,不慌,到后面,都会一一讲清楚,讲明白...

在上面的代码中,我们将传进来的getter中的所有属性全部复制了一份绑定到了this.getter上。 存在这样一个疑问就是我们为啥不直接让this.getter直接指向options.getter干嘛还要多此一举
像下面这样写不是更加简洁吗?而且还更节省空间。

class Store{
    constructor(options){
        this.state = options.state;
        this.getters = options.getters;    
    }
}
var store = new Store({
    state:{
        name:'iamsmiling'
    },
    getters:{
        getName:(state)=>state.name
    }
})

哇,看上去好好有道理啊!
不过,存在这样一个问题,我们store.getters.getName时,我们得到的时是一个函数对象,也就是(state)=>state.name.

也许你会说,这简单啊,我们直接再加个括号不就完事了吗?但真的是这样吗? store.getters.getName(),报错了因为getName()没有传递参数。

那我们再加个参数进去呗,于是变成了这个样子store.getters.getName(store.state) 最后,我们终于如愿得到了我们想要的iamsmilling

但我们再回头看一下,在vuex中,我们是如何调用的

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})
store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]

对比一下,我们实现的store.getters.getName(store.state)store.getters.doneTodos,我们的版本显然很鸡肋。

有什么办法可以改善呢?我们模仿Vuex源码的方式,对我们的代码进行修正和完善:

class Store{
  constructor(options){
    this.data = options.state;
    let getters = options.getters || {}
    this.getters = {}
    // 把getter对象上的属性全部绑定到this.getter上
    Object.keys(getters).forEach((key) => {
      Object.defineProperty(this.getters, key, {
        get: () => getters[key](this.state)
      })
    })
  }
  get state(){
      return this.data
  }
}
var store = new Store({
  state: {
    name: 'iamsmiling'
  },
  getters: {
    getName: (state) => state.name
  }
})
console.log(store.getters.getName) // 输出iamsmiling

现在,我们也可以通过store.getters.getName来进行访问了,姿势也变得优雅了。