辅助函数
1. mapState
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default {
computed: {
localComputed () ,
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
// ...
})
}
}
computed: mapState([
// 映射 this.count 为 store.state.count
'count'
])
export default {
// ...
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
- 其实使用过 Vuex 的同学都知道,我们在页面或者组件中都是通过
this.$store.xxx
来调用的,那么其实,我们只要把你所创建的store对象赋值给页面或者组件中的$store变量即可
2. mapGetters
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)
}
}
})
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
...mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
3. mapActions
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
// `mapActions` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
})
}
}
源码
全局混入Mixin
- Vuex的原理通俗讲就是:利用了全局混入Mixin,将你所创建的store对象,混入到每一个Vue实例中,那么全局混入是什么呢?举个例子:
import Vue from 'vue'
// 全局混入
Vue.mixin({
created () {
console.log('handsome Boy')
}
})
// 之后创建的Vue实例,都会输出'handsome Boy'
const a = new Vue({
// 这里什么都没有,却能实现输出'handsome Boy'
})
// => "handsome Boy"
const b = new Vue({
// 这里什么都没有,却能实现输出'handsome Boy'
})
// => "handsome Boy
上面例子看懂的人,就知道了,同理,把console.log(‘handsome Boy’)这段代码换成一段能做这件事的代码:把store赋值给实例的$store属性,就实现了:
代码实现
// vuex.js
let Vue;
// install方法设置,是因为Vue.use(xxx)会执行xxx的install方法
const install = (v) => { // 参数v负责接收vue实例
Vue = v;
// 全局混入
Vue.mixin({
beforeCreate() {
if (this.$options && this.$options.store) {
/ * 根页面,直接将身上的store赋值给自己的$store,至于怎么判断是根页面的, 看最下面的解析1 .
这也解释了为什么使用vuex要先把store放到入口文件main.js里的根Vue实例里*/
this.$store = this.$options.store;
} else {
// 除了根页面以外,将上级的$store赋值给自己的$store
this.$store = this.$parent && this.$parent.$store;
}
},
})
}
// 创建类Store
class Store {
constructor(options) { // options接收传入的store对象
this.vm = new Vue({
// 确保state是响应式
data: {
state: options.state
}
});
// getter
let getters = options.getters || {};
this.getters = {};
console.log(Object.keys(this.getters))
Object.keys(getters).forEach(getterName => {
Object.defineProperty(this.getters, getterName, {
get: () => {
return getters[getterName](this.state);
}
})
})
// mutation
let mutations = options.mutations || {};
this.mutations = {};
Object.keys(mutations).forEach(mutationName => {
this.mutations[mutationName] = payload => {
mutations[mutationName](this.state, payload);
}
})
// action
let actions = options.actions || {};
this.actions = {};
Object.keys(actions).forEach(actionName => {
this.actions[actionName] = payload => {
actions[actionName](this.state, payload);
}
})
}
// 获取state时,直接返回
get state() {
return this.vm.state;
}
// commit方法,执行mutations的'name'方法
commit(name, payload) {
this.mutations[name](payload);
}
// dispatch方法,执行actions的'name'方法
dispatch(name, payload) {
this.actions[name](payload);
}
}
// 把install方法和类Store暴露出去
export default {
install,
Store
}
使用解析
// index.js
import Vue from 'vue';
import vuex from './vuex'; // 引入vuex.js暴露出来的对象
Vue.use(vuex); // 会执行vuex对象里的install方法,也就是全局混入mixin
// 实例一个Store类,并暴露出去
export default new vuex.Store({
state: {
num: 1
},
getters: {
getNum(state) {
return state.num * 2;
}
},
mutations: { in (state, payload) {
state.num += payload;
},
de(state, payload) {
state.num -= payload;
}
},
actions: { in (state, payload) {
setTimeout(() => {
state.num += payload;
}, 2000)
}
}
})
// main.js
import Vue from 'vue';
import App from './App.vue'
import store from './store/index'; // 引入刚刚的index.js
new Vue({
store, // 把store挂在根实例上
el: '#app',
components: {
App
},
template: '<App/>',
})
解析补充
- 我们打印一下工程项目中最开始的实例对象
打印结果 :
因此创建vue实例后, $opations 可以拿到Store的所有数据。