Vue.js 前端开发实战之 07-Vuex 状态管理
AI 摘要
初识 Vuex
Vuex 概述
Vuex 是 Vue 官方提供的一套组件状态(即数据)管理和维护的解决方案。
Vuex 作为 Vue 的插件来使用,进一步完善了 Vue 基础代码功能,使 Vue 组件状态更加容易维护,为大型项目的开发提供了强大的技术支持。
Vuex 初体验
Vuex 3.x 文档:https://vuex.vuejs.org/zh/
Vuex 的使用:
- 新建 HTML 文件,并使用 script 标签引入 vue.js、vuex.js。
- 创建 Vuex 的“数据仓库” Store 对象,并初始化数据。
- 实例化 Vue 实例,并将 Store 对象传递给 Vue 实例。
- 在 app 盒子中,通过 this.$store.state 获取数据。
示例:Vuex 初体验
入口页面(index.html):
<div id="app">
<!--
通过 this.$store.state.参数名 取值
-->
<p>{{this.$store.state.name}}</p>
</div>
<script>
// 创建Vuex数据仓库对象
let store = new Vuex.Store({
// state:状态即数据
state: {
name: 'hello,Vuex'
}
})
let vm = new Vue({
el: '#app',
// 挂载Vuex实例,等同于store: store
store,
})
</script>示例效果:
Vuex Store 中的数据是响应式的,在组件中调用 Store 中的数据,除了可以使用 this.$store.state 外,还可以使用计算属性的方式获取数据。
示例:通过计算属性获取数据
入口页面(index.html):
<div id="app">
<!--
通过计算属性生成参数
-->
<p>{{name}}</p>
</div>
<script>
let store = new Vuex.Store({
state: {
name: 'hello,Vuex'
}
})
let vm = new Vue({
el: '#app',
store,
computed: {
name() {
// 在计算属性中返回store中的数据
return this.$store.state.name
}
}
})
</script>当一个组件需要获取多个数据时,将 store 中的数据都声明为计算属性有些麻烦,Vuex 提供了 mapState 辅助函数来生成计算属性。
示例:通过 mapState 生成计算属性
入口页面(index.html):
<div id="app">
<!--
通过Vuex.mapState批量生成计算属性
-->
<p>{{name}}</p>
</div>
<script>
let store = new Vuex.Store({
state: {
name: 'hello,Vuex'
}
})
let vm = new Vue({
el: '#app',
store,
computed: {
// ...:展开运算符,将mapState的结果放到计算属性中
//
...Vuex.mapState(['name'])
}
})
</script>Vuex 状态管理模式
在 Vue 中,组件的状态(数据)变化是通过 Vue 单向数据流的设计理念实现的。
在组件系统中,单向数据流是指父组件通过属性 props 传递数据到子组件,子组件不能直接修改从父组件接收的 props,而是应该通过自定义事件来通知父组件进行数据更新。
Vue 的单向数据流增强了组件之间的独立性,但是存在多个组件共享数据的时候,单向数据流就难以对数据进行维护。
Vuex 就是专门为 Vue 设计的状态(数据)管理库,利用 Vue 的细粒度数据响应机制来进行高效的状态更新。
Vuex 配置选项
mutations
在 Vuex 中,不能直接修改 store 中的数据,必须调用相应的事件处理方法处理 state 数据。
如果直接修改 store 中的数据,视图页面会发生变化,但 store 中的数据实际上并没有发生变化。
示例:直接修改 store 中的数据
入口页面(index.html):
<div id="app">
<button @click="click1">直接 count++</button>
<p>{{this.$store.state.count}}</p>
</div>
<script>
let store = new Vuex.Store({
state: {
count: 0
}
})
let vm = new Vue({
el: '#app',
store,
methods: {
click1() {
this.$store.state.count++
}
}
})
</script>示例效果:
mutations 选项用来定义事件处理方法,用于处理 state 数据,调用 mutations 中的方法,就可以完成数据更新。
示例:使用 mutations 提交数据更新
入口页面(index.html):
<div id="app">
<button @click="click1">直接 count++</button>
<button @click="click2">使用mutations修改count</button>
<p>{{this.$store.state.count}}</p>
</div>
<script>
let store = new Vuex.Store({
state: {
count: 0
},
// mutations:定义数据处理方法
mutations: {
// state:Vuex.Store.state对象
// param:要修改的新数据
updateCount(state, param) {
// 让Store中的数据等于新的数据
state.count = param
}
}
})
let vm = new Vue({
el: '#app',
store,
methods: {
// ...
click2() {
// 通过this.$store.commit()调用mutations中的更新数据的方法
// 参数1:调用的方法名
// 参数2:新的参数的值,可以不传
this.$store.commit('updateCount', 100)
}
}
})
</script>示例效果:
mutations 中定义的方法是同步函数,组件数据发生变化时,触发 mutations 中的事件处理方法来更新数据,这是一种同步更新,在 mutations 中,不能有异步操作。
示例:使用 mutations 异步更新数据
入口页面(index.html):
<div id="app">
<button @click="click1">直接 count++</button>
<button @click="click2">使用mutations修改count</button>
<button @click="click3">3秒钟后修改count</button>
<p>{{this.$store.state.count}}</p>
</div>
<script>
let store = new Vuex.Store({
state: {
count: 0
},
mutations: {
updateCount(state, param) {
// 定时器:三秒后修改数据(异步操作)
setTimeout(function () {
state.count = param
}, 3000)
}
}
})
let vm = new Vue({
el: '#app',
store,
methods: {
// ...
click3() {
this.$store.commit('updateCount', 100)
}
}
})
</script>示例效果:
actions
actions 和 mutations 类似,都是用于定义事件处理方法的。
actions 定义的方法,可以执行异步操作,actions 的本质还是调用 mutations。
示例:使用 actions 异步更新数据
入口页面(index.html):
<div id="app">
<button @click="click1">直接 count++</button>
<button @click="click2">使用mutations修改count</button>
<button @click="click3">3秒钟后修改count</button>
<button @click="click4">3秒钟后修改count(actions)</button>
<p>{{this.$store.state.count}}</p>
</div>
<script>
let store = new Vuex.Store({
state: {
count: 0
},
// 同步方法
mutations: {
updateCount(state, param) {
state.count = param
}
},
// 异步方法
actions: {
// context:即$store对象
// param:要修改的新数据
updateCount(context, param) {
// 定时器:三秒后修改数据(异步操作)
setTimeout(function () {
// 调用$store.commit执行同步更新
// actions的本质还是mutations
context.commit('updateCount', param)
}, 3000)
}
}
})
let vm = new Vue({
el: '#app',
store,
methods: {
// ...
click4() {
// 通过this.$store.dispatch()调用actions中的更新数据的方法
this.$store.dispatch('updateCount', 100)
}
}
})
</script>示例效果:
getters
Vuex 允许在 store 中定义 getters 计算属性,类似于 Vue 实例的 computed,getters 返回值会根据它的依赖进行处理然后缓存起来,且只有当它的依赖值发生变化时才会重新计算。
示例:getters
入口页面(index.html):
<div id="app">
<p>单价:{{this.$store.state.price}}</p>
<p>数量:{{this.$store.state.count}}</p>
<p>总价:{{this.$store.getters.totalPrice}}</p>
<p>
<button @click="plus">+1</button>
<button @click="minus">-1</button>
</p>
</div>
<script>
let store = new Vuex.Store({
state: {
price: 10,
count: 0
},
mutations: {
plus(state) {
state.count++
},
minus(state) {
state.count--
}
},
// 定义Vuex的计算属性
getters: {
totalPrice(state) {
return state.price * state.count
}
}
})
let vm = new Vue({
el: '#app',
store,
methods: {
plus() {
this.$store.commit('plus')
},
minus() {
this.$store.commit('minus')
}
}
})
</script>示例效果:
modules
Vuex 提出了类似于模块化开发的方式对 store 进行管理。
modules 用于在 store 中定义模块对象。
示例:modules
入口页面(index.html):
<div id="app">
<!--
通过 this.$store.state.模块名.xxx 调用
-->
<p>{{this.$store.state.a.count}}</p>
<p>{{this.$store.state.b.count}}</p>
</div>
<script>
// 定义模块A对象
let moduleA = {
state: {
count: 1
}
}
// 定义模块B对象
let moduleB = {
state: {
count: 2
}
}
let store = new Vuex.Store({
// 定义模块
modules: {
// 模块名称: 模块对象
a: moduleA,
b: moduleB
}
})
let vm = new Vue({
el: '#app',
store
})
</script>示例效果:
plugins
plugins 是 Vuex 中的插件配置选项,用于为 Vuex 添加插件。
示例:plugins
入口页面(index.html):
<div id="app">
</div>
<script>
// 自定义一个插件
// 插件本身是一个方法
// store:Vuex.Store对象
let myPlugin = function(store) {
// subscribe方法:处理mutations
// 每次mutations提交后都会执行这个方法
// mutation:调用的同步方法的信息
store.subscribe((mutation, state) => {
// mutation.type:调用了什么方法
// mutation.payload:传进来什么参数
console.log("调用mutation方法:" + mutation.type + ",参数为:" + mutation.payload)
})
}
let store = new Vuex.Store({
// 指定插件列表
plugins: [myPlugin],
mutations: {
do(state) {
console.log('do被执行了')
}
}
});
store.commit('do', 'hello')
let vm = new Vue({
el: '#app',
store
})
</script>示例效果:
devtools
devtools 用于设置是否在 vue-devtools 中启用 Vuex 跟踪调试。
示例:devtools
入口页面(index.html):
let store = new Vuex.Store({
devtools: false,
// ...
})Vuex API
模块注册
Vuex store 提供了动态创建模块的方法 store.registerModule。
示例:store.registerModule
入口页面(index.html):
let store = new Vuex.Store({})
// 参数1:模块名称
// 参数2:模块对象
store.registerModule('myModule', {
state: {}
})状态替换
Vuex 提供了状态替换的方法 store.replaceState。
应尽量避免使用这个方法,在错误的位置使用这个方法会造成数据被错误覆盖。
示例:store.replaceState
入口页面(index.html):
let store = new Vuex.Store({
state: {
count: 0
}
})
// 参数1:要替换的新的state对象
store.replaceState({
count: 1
})