前几天看了动脑学院讲的vuex,觉得真心不错,核心的基本都讲到了。这两天去翻了下官网的文档,然后在vue-cli上实现了那个计数案例。现记录下一些学习笔记。
首先,借用下官网的经典图:
这图的执行顺序是这样的:
1、组件通过Dispatch触发Actions里面的动作;
2、Actions通过Commit提交Mutations
3、Mutations注册事件,通过这些事件来改变State的状态
4、最后State状态改变完后渲染到组件上
接下来来了解一下vuex的一些核心:
1、State
用来存储一些源数据,然后你可以直接在组件的计算属性中通过$store.state来获取数据,如下:
computed: {
count () {
return this.$store.state.count;
}
}
也可以直接通过mapState来获取,下面的计数案例就是通过这种方法来获取的。
2、Getter
这个也可以用来获取State里的源数据,如下:
const store = new Vuex.Store({
state: {
msg:'hello vue'
},
getters: {
msg: function(state){
return state.msg;
}
}
})
然后就可以在组件上通过$store.getters.msg来获取了。
Getter还可以用来对数据进行操作后再返回,例如过滤,如下:
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: function(state){
return state.todos.filter(function(todo){ return todo.done; })
}
}
})
这是官网的案例,es6的部分被我改了,它返回todos数组中done为true的对象。其中的filter它会遍历数组的每一项,然后返回其中为true的项并返回新的数组(不会改变原数组)。虽然你也可以直接在组件中获取数据后再对数据进行过滤处理,但是如果多个组件需要用到的话,那么就要重复写代码了,反之用getter就轻松多了。
Getter可以看做是vuex的计算属性,getter的返回值会根据他的依赖被缓存起来,且只有当它的的依赖值发生改变才会被重新计算。同State一样,也可以用mapGetters来获取。如下:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodos'
// ...
])
}
}
3、Mutations
mutations用来注册一些事件,然后通过这些事件来改变state的状态。接受state为第一参数:如下
const store = new Vuex.Store({
state: {
count: 11
},
mutations: {
add(state) {// 变更状态
state.count++
}
}
})
一条重要的原则就是:要记住
mutations必须是同步函数。(自己也不是很理解)
4、Action
改变state状态的事件注册完了,那要如何触发呢?那就是Action啦。如下:
const store = new Vuex.Store({
state: {
count: 11
},
mutations: {
add (state) {//变更状态
state.count++
}
},
actions: {
add(context) {
context.commit('add')
}
}
})
然后就可以直接在组件中通过this.$store.dispatch('add')触发action,或者使用mapActions来触发,如下:
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'add', // 将 `this.add()` 映射为 `this.$store.dispatch('add')`
]),
}
}
总结:总之整个流程就是,组件中通过dispatch或者mapActions触发Action,然后Action中通过commit提交mutations来触发mutations中注册的事件,最后事件改变state的状态并更新到组件中。
理解完这些后开始我们的案例:
首先下载vue-cli,之前有说过,这里就不在说了。
然后是安装vuex,在命令行中进入自己的vue-cli项目,然后输入:cnpm install vuex --save
安装完后就是引入并使用了,我是直接在src文件夹下建立了一个store文件夹和store.js文件,然后在store.js中引入vue和vuex,然后实例化一个仓库,主要代码如下
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
count:11
}
const mutations = { //注册事件,处理状态变化
add:function(state){
state.count++;
},
reduce:function(state){
state.count--;
}
}
const actions = { //处理你要干什么
add(context){
context.commit('add');
},
reduce(context){
context.commit('reduce');
}
}
const store = new Vuex.Store({
state,
mutations,
actions
})
export default store
然后在main.js中引入store.js文件,并注入到vue实例上:
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store/store.js'
Vue.config.productionTip = false;
//Vue.use(Vuex);
/* eslint-disable no-new */
new Vue({
el: '#app',
store,
router,
template: '<App/>',
components: { App }
})
接下来就可以在组件上通过mapActions提交mutations和mapStates来获取state的状态了
具体如下:
<template>
<div id="app">
<input type="button" value="add" @click="add" />
<input type="button" value="reduce" @click="reduce" />
<p>当前的数字为:{{count}}</p>
</div>
</template>
<script>
import {mapState,mapActions,mapGetters} from 'vuex'
export default {
name: 'app',
computed:mapState({
count:function(state){
return state.count;
}
}),
methods:{
...mapActions([
'add', // 将 `this.add()` 映射为 `this.$store.dispatch('add')`
'reduce'
])
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
效果如下: