Vuex入门(1)—— Vuex的设计初衷和简单使用
开一个Vuex的坑.
先来谈谈个人看法,之前很早的时候就用过Vuex做组件间通信,对于单页面应用来说,也就是不同的router子组件的一些数据通信,当然我也尝试过event bus的解决方案,这里不进行横向对比了,如果想做组件间的复杂通信,直接选择Vuex即可(个人建议).如果有人想学习Vuex,个人推荐是直接去官网的API,当然官网的API会让你先了解一下ES6的语法,当时也是看到那句话就比较反感那个文档,不过还是屁颠屁颠的把ES6的语法过了一遍,有兴趣的可以去我的分类里简单学习一下.关于这个系列肯定会有后续的展开,主要包括一些Vuex的核心概念(State,Getter,Mutation,Action,Module),但个人推荐不用深入了解Vuex,如果需求不是那么复杂的话,基本上你稍微了解一下今天的例子,知道如何用state存储状态,如何用mutation触发状态变更就可以完成大部分项目需求.
Vuex的设计初衷就是为了解决Vue中单项数据流的问题,什么是单项数据流,简单来说就是
父组件可以传值给子组件,你可以用props,还相对简单.
子组件可以传值给父组件,你可以用$emit,这个算相对难一丢丢.
这并不是单项数据流的官方解释,是我自己随便总结的,来看这种数据交互方式会产生什么问题
1.祖祖祖父组件要传值给曾曾曾孙,这就有点尴尬了,一个简单的数据要从祖宗十八代传到你这一代,得经历子组件的一个个祖辈,而且中间还不能断,这又不是传家宝,传那么多次又不会升值,所以这个问题是Vue的设计中未考虑完善的.
2.兄弟节点间的通信问题,可能需要父组件的支持,然而凭什么你和你兄弟的事情非得让你爸知道呢?这个问题在Vue的设计中也不好解决.
为了解决上述问题,Vuex提出了一个'公共仓库'(store)的概念,“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state).你的所有组件都可以访问这个容器中的公共状态,这有点像你定义了一个全局变量,因此你可以在当前代码块的所有位置访问到这个变量.当然store容器和全局变量还是有很大的区别的.
1.Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
2.你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
前面两点是官网的说明,谈谈个人理解,首先第一点,由于使用Vuex需要将store实例挂载到Vue实例中,因此Vue实例可以对Vuex的state数据加监听,这跟Vue实例data的数据双向绑定是类似的.而全局变量由于没有被"数据劫持",因此即使全局变量的值发生改变,也无法在Vue实例中监听到他的变化.第二点更好理解一些,就是Vuex中的状态值,不能通过赋值的方式(state.xxx = yyy)改变,需要通过mutation触发变更,这样做方便状态管理,而一般的全局变量是支持直接赋值的.
下面来实现一个简单的例子,用vuex做一些事情
首先,项目是基于vue-cli脚手架搭的,你可以用npm的方式导入vuex,并通过Vue.use(Vuex)的显示声明方式来使用Vuex
在项目中,我通过store文件夹来管理vuex的一些模块,今天要用到的模块只有state模块和mutation模块,这也是Vuex状态管理的最基本的两个模块.
要使用Vuex,你还需要在main.js的Vue根实例中挂载一下store实例,如下所示
//main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store/index'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store, // 挂在store到所有子组件中
components: { App },
template: '<App/>'
})
准备工作都完成了.我们在store里面存一个count用于后续操作.
//state.js
let state = {
count: 1
}
export default state
存入后,我们就可以在任意子组件中访问这个值了,在vue的子组件中我们可以通过this.$store访问store对象,注意这里我用了computed接收了store的值,这有利于在值发生改变的时候及时的响应到当前子组件.
<template>
<div id="example">
{{count}}
</div>
</template>
<script>
export default {
computed: {
count () {
return this.$store.state.count
}
},
methods: {
}
}
</script>
<style lang="less" scoped>
</style>
完成了值的接收,下面来对这个值进行一些操作,注意,如果要操作state中的值,不能直接通过this.$store.state.xxx = yyy的方式进行暴力修改,必须要提交给mutation处理,这在之前也有提过,所以我们要在mutation.js里写入对state的操作
//mutation.js
// 第一个参数默认接收state对象
let increment = (state) => {
state.count++
}
let decrement = (state) => {
state.count--
}
export {increment, decrement}
然后我们就可以通过this.$store.commit('function')修改这个值了.
<template>
<div id="example">
<button @click="decrement">-</button>
{{count}}
<button @click="increment">+</button>
</div>
</template>
<script>
export default {
computed: {
count () {
return this.$store.state.count
}
},
methods: {
increment () {
this.$store.commit('increment')
},
decrement () {
this.$store.commit('decrement')
}
}
}
</script>
<style lang="less" scoped>
</style>
这里没有涉及到通信的问题,但事实上Vuex已经帮你做了状态管理了,如果别的子组件用到了上述的count,在count改变的时候,其他的子组件也会相应到count的改变,有兴趣的自己动手试一试,这里不婆婆妈妈啰啰嗦嗦了.
后续文章会深入探究Vuex的API和坑,欢迎关注~