Vuex
概念
是什么
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
- 状态管理模式:
Vuex提供了一个全局环境,我们可以在这个环境中声明全局变量。这个变量我们称为状态,Vuex就是管理这个状态(全局变量)。 - 集中式:所有的状态都是在同一个地方声明和管理。
- 可预测:改变状态(全局变量),
Vuex有固定的方法来改变。
为什么
vuex 是采用集中式管理组件依赖的共享数据的一个工具,可以解决不同组件数据共享问题。
state:声明所有全局变量mutaitions:vuex提供专门用来修改state状态的方法。注意!不可以写异步代码。actions:vuex提供可以异步修改state状态的方法。
总结
- 修改
state状态必须通过mutations。 mutations只能执行同步代码,类似ajax,定时器之类的代码不能在mutations中执行。- 执行异步代码,要通过
actions,然后将数据提交给mutations才可以完成。 state的状态即共享数据可以在组件中引用。- 组件中可以调用
action。
vuex的机制,是一种闭环的状态
使用
环境初始化
- 下载依赖
npm i vuex@3 - 引入
import Vuex from "vuex" - 注册
Vue.use(Vuex) - 实例化
const store = new Vuex.Store({ state: { a: 1 } }) - 挂载
new Vue({ // 5、挂载 // store: store, store, render: h => h(App), }).$mount('#app')
state
state 是放置所有公共状态的属性,如果你有一个公共状态数据 , 你只需要定义在 state 对象中。
定义
const store = new Vuex.Store({
state: {
count: 0
}
})
使用
原始形式
直接使用插值表达式来获取store对象实例。
<p>{{$store.state.count}}</p>
计算属性
优化使用,将state属性定义在计算属性中。
<p>{{count}}</p>
computed: {
count(){
return this.$store.state.count
}
}
这样可以实现简写。
辅助函数
- 引入辅助函数。
// 引入辅助函数,我们可以通过辅助函数获取store中全局变量 import { mapState } from "vuex"; - 在计算属性中使用辅助函数。
computed: { // 这个辅助函数最终解析出来和计算属性优化使用是一样的 ...mapState(['count']), } - 在结构中直接使用变量获取
store中的值。<p>{{a}}</p>
mutations
state 数据的修改只能通过mutations ,并且 mutations 必须是同步更新,目的是形成数据快照。
数据快照:一次
mutation的执行,立刻得到一种视图状态,因为是立刻,所以必须是同步。
定义
const store = new Vuex.Store({
state: {
count: 0
},
// 定义mutations
mutations: {
// 方法里参数 第一个参数是当前store的state属性
// payload 载荷 运输参数 调用mutaiions的时候 可以传递参数 传递载荷
addCount (state,payload) {
state.count += payload
}
}
})
使用
原始形式
创建一个 button 按钮,点击按钮调用 mutations 内的方法名称。
<button @click="add">点我</button>
methods: {
add(){
// 语法:this.$store.commit("mutation中的函数名", 参数1)
this.$store.commit("setCount",5)
}
}
辅助函数
- 导入
mapMutations。import { mapMutations } from "vuex"; - 用数组的形式解构引入。
methods: { ...mapMutations(["setCount"]), } - 在结构中直接使用方法名,想要传值可直接用括号传值。
<button @click="setCount(5)">点我</button>
注意:
修改数据必须通过
mutations来修改,如果没有经过mutations修改数据,页面上的数据会被修改,但store内的数据没有被真正修改。而且在严格模式下还会报错。
action
state 是存放数据的,mutations 是同步更新数据, actions 则负责进行异步操作。
定义
actions: {
// 定义函数,进行异步操作,通过调用mutations函数从而修改state的值
asyncCount(context){
// context:表示当前的store实例
setTimeout(()=>{
// 调用mutations中的setCount函数,从而修改count值
context.commit("setCount",2)
},1000)
}
}
使用
原始形式
methods: {
setCount(){
this.$store.dispatch("asyncCount")
}
}
如果需要传参的话就在后面加个逗号即可,如下所示。
setCount () {
this.$store.dispatch('getAsyncCount', 123)
}
辅助函数
- 引入辅助函数。
import { mapActions } from "vuex"; - 将
actions中的函数解构到methods中。methods: { ...mapActions(["asyncCount"]), } - 直接调用函数。
<button @click="asyncCount">点我</button>
getters
除了 state 之外,有时我们还需要从 state 中派生出一些状态,这些状态是依赖 state 的,此时会用到 getters 。
定义
getters: {
// 定义函数,并且函数可以默认接受到state参数
// 这个函数名当做普通变量进行使用的
fileList(state){
return state.list.filter(item=>item>5)
},
student(state){
return state.obj.student.home
}
},
使用
原始形式
- 操作数据
<p>{{$store.getters.fileList}}</p> // [6,7,8,9] - 简化步骤
<p>{{$store.state.obj.student.home}}</p> // zhanjiang <p>{{$store.getters.student}}</p> // zhanjiang
辅助函数
- 引入辅助函数。
import { mapGetters } from "vuex"; - 利用辅助函数把getters中的数据解构为计算属性。
computed: { ...mapGetters(["fileList"]), }, - 使用计算属性展示数据。
<p>{{ fileList }}</p>
modules
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
即如果把所有的状态都放在
state中,当项目变得越来越大的时候,Vuex会变得越来越难以维护。
由此,又有了Vuex的模块化
定义
const store = new Vuex.Store({
modules: {
// user模块
user: {
state: {
token: '1234'
}
},
// setting模块
setting: {
state: {
name: 'vuex实例'
}
}
}
})
使用
原始形式
<!-- 如何获取模块中的数据进行使用? -->
<!-- 答:通过以下语法:this.$store.模块名.变量 -->
<h1>token: {{$store.state.user.token}}</h1>
<h1>name: {{$store.state.setting.name}}</h1>
辅助函数
- 通过getters获取模块中的数据。
getters: { token(state){ return state.user.token }, name: (state)=>{ return state.setting.name } } - 利用getters的辅助函数,将数据变量解构为计算属性。
<script> import { mapGetters } from "vuex"; export default { computed: { ...mapGetters(["token","name"]) } } </script> - 使用计算属性。
<h2>简写token: {{token}}</h2> <h2>简写name: {{name}}</h2>
高封闭性
默认情况下,模块中的 mutations 、 actions 、 getters 都是注册在 vuex 全局下的,和写在外面的引用方式是一样的。
如果取一样的名字,会造成冲突的风险。
如果我们想保证内部模块的高封闭性,我们可以采用 namespaced 来进行设置。
// 能够拿到数据
<button @click="$store.commit('setName')">测试直接调用模块中的mutations函数</button>
<script>
const store = new Vuex.Store({
modules: {
// setting模块
setting: {
state: {
name: 'vuex实例'
},
mutations: {
setName(state) {
console.log(state);
}
}
}
},
})
</script>
作用
使得模块内的 mutations 、 actions 、 getters 等变成局部属性。
使用
直接调用
setting: {
namespaced: true,
state: {
name: 'vuex实例'
},
mutations: {
setName(state) {
console.log(state);
}
}
}
现在直接拿会报错,提示找不到这个函数。
如何获取局部中的 mutations 函数呢?
在调用前需要加模块名,语法如下所示:
$store.commit('模块名/函数名')
中间用逗号隔开。
<button @click="$store.commit('setting/setName')">测试直接调用模块中的mutations函数</button>
现在就能获取到函数了。
辅助函数
<button @click="updateToken">测试辅助函数调用模块中的mutations函数</button>
methods: {
...mapMutations("user",["updateToken"])
}
createNamespaceHelpers
命名空间的辅助函数
- 引入命名空间辅助函数。
import { createNamespacedHelpers } from "vuex"; - 通过命名空间辅助函数传入模块名,从而获得到该模块的mutations辅助函数,并重命名。
const { mapMutations:usermap } = createNamespacedHelpers("user") - 利用获取到的mapmutations辅助函数获取到user模块的函数。
methods: { ...usermap(["updateToken"]) } - 直接使用。
<button @click="updateToken">测试辅助函数调用模块中的mutations函数</button>
拓展:解决重名问题
- computed中原来的属性名和getters中的名字重名。
- 自定义函数和引入的辅助函数重名。