Vuex 状态管理模式
一、是什么?
vue官方的一个插件 npm包 作用:实现组件之间的数据共享
是个全局变量 像个数据池 大范围的数据共享
在哪需要它?
大项目 适合中大型单页应用
二、怎么使用
怎么使用 :看官网文档
1.安装
(vue2 要安装vuex@3, vue3 要安装vuex@4)
vue2
npm i vuex@3 -S
vue3
yarn add vuex 或 npm install vuex --save
2.配置 实例化store
新建store文件->index.js, 实例化store对象 导出store对象
在store的index里new了一个实例对象赋值给store , export default导出去了
// 1.引入 Vue 和 Vuex 包
import Vue from 'vue'
import Vuex from 'vuex'
(类似于data(){return {a:1, b:2,xxxxxx}})
// 2.向vue中注册vuex 让 vue 使用 Vuex
Vue.use(Vuex)
// 3. new Vuex.Store() 实例化store对象,并设置state数据池和mutations方法集
const store = new Vuex.Store({
state: { //存所有数据,相当于data(){return {num:1, uname:'aaa'}
num:1
uname:'aaa'
},
getters: { // vuex中的计算属性
},
mutations: { //同步方法,操作state方法
addNum(state){
state.num++ //同步方法每次加1
},
},
actions: { // 异步方法, 操作mutation
},
modules: { // 模块
},
// 4.导出store对象
export default store
3. main.js中,将 store 实例对象导入注入到Vue根组件中
进行引入store,在所有组件中就可以使用了(因为new的是vue是根实例)
从main.js导入 store 注入进 Vue根实例,注入之后 vue身上就多了 store ,
import Vue from 'vue' // Vue 是一个构造函数 所以要大写
import App from './App.vue'
import router from './router'
import store from './store' // 这里就省略了index.js
new Vue({
// 挂载实例对象
router,
store,
render: h => h(App)
}).$mount('#app')
拓展1.import引入
./ 开头, webpack会把这个当成我们自己的组件来加载,在自己当前的文件里找
没有./,则webpack会把这个当成第三方包来加载
如果引入index取名的文件可以省略不写,写上也没有任何问题。
拓展2:
要渲染到public文件夹下面的index.html里的id="app"两种方式 一种el
new Vue({
el:'#app'
})
// 完全等价于下面写法
new Vue({
}).$mount('#app')
4.state的使用 ,定义公共数据格式,可以在任何组件中进行调用
export default new Vuex.Store({
// 存所有的数据,相当于data
state: {
num:1
},
})
state是响应式的:如果修改了数据,相应的在视图上的值也会变化.
每次敲完代码,记得去网页中使用vue-devtool调试工具查看
三、核心概念
vuex分为五个大块 使用
state: 统一定义公共数据(类似于data(){return {a:1, b:2,xxxxxx}})
mutations : 使用它来修改数据(类似于methods)
getters: 类似于computed(计算属性,对现有的状态进行计算得到新的数据-------派生 )
actions: 发起异步请求
modules: 模块拆分
5.1 State
组件访问 State 数据 使用公共数据
1>{{$store.state.属性名}} 在标签中直接使用,可以省略this,
{{$store.state.属性名}} {{$store.state.num}}
2>this.$store.state.属性名 组件js里通过this.$store就能访问到
this.$store.state.属性名 this.$store.state.num
在组件中通过 computed 使用 vuex 数据池里的变量,
(不能写在data里 一旦写在data里 my_num不会变化
一定要写在computed里
data() 里的变量是死的 num赋值给my_num 你不主动修改my_num 它是不会变的)
5.2 Mutation 里面的方法一般全大写
addNum 需要替换成 ADD_NUM
(1) 用mutations修改公共数据 在store/index.js里
特点:要修改State 的数据,只能调用Mutation 方法,Vuex中修改公共数据的唯一入口。
好处:能够确保修改来源的唯一性,方便调试和后期维护。
mutations: { //同步方法,操作state方法
addNum(state){
state.num++ //同步方法每次加1
},
改变数据池里的数据只能通过commit触发mutations里的某个函数)修改state里的数据,否则生不成快照
this.$store.commit('mutations里的函数名')
通过dispatch()方法触发 actions异步获取数据
this.$store.dispatch('actions里的函数名')
methods: {
add() {
// commit()的第一个参数是mutations里的函数名
// 调用addNum方法 改变数据 用commit() this.$store.commit('mutations里的函数名')
this.$store.commit("addNum");
// 但是强烈不推荐这么写!!!
// this.$store.state.num++;
},
},
拓展: 开启严格模式
数据不能在组件内直接修改 强烈不推荐这么写!!! // this.$store.state.num++;
一定通过mutations去改变数据池里的数据,虽然不会报错,但这样不能生成数据快照.
dev-tools只监听mutations里函数的执行情况.函数执行一次就生成一个数据快照)
作为项目经理,为了防止底下的人私自使用这种错误方法,可以在vuex中写上:
vue创建 store 的时候传入 strict : true, 开启严格模式,
那么任何修改state的操作,只要不经过 mutation处理的函数,vue就会报错;
// 判断现在是开发环境还是生产环境,如果是开发环境就开启严格模式,否则关闭
strict: process.env.NODE_ENV !== 'production',
(2)简写
如果一个组件是需要使用很多vuex中的数据或方法就可以集体导入
第一步、引入...mapState 和 ...mapMutations 方法 从展示页面的js代码中
import { mapState, mapMutations } from "vuex";
第二步、集体导入数据和方法
...mapState方法 在computed 集体导入vuex中的state里的数据
...mapMutations方法 在methods 集体导入mutations里的方法
...mapMutations(["addNum"])
// 等价于下面写法
// addNum(state) {
// state.num++;
// },
方法可以互相使用 既然上面已经引入addNum()方法 还可以用this调用 实现
// myAddNum() {
// this.addNum();
// },
myAddNum() {
this.addNum();
},
第三步、在html代码里直接使用vuex里mutations方法集的方法
<h3>Right 组件{{num}} {{$store.state.num}}</h3>
<p>{{uname}}</p>
<button @click="myAddNum">加1</button>
<button @click="addNum">+1</button>
(3) 传参数
第一种:
调用mutations可以传值
不是加1 每次加2
main.js
mutations:{
// 固定 第一个参数永远是state,第二个参数永远是调用者传进来的值
addNum(state,val){ // 接收第二个参数
// state.num++
state.num+=val
},
第一种 用commit去写
<h3>Right 组件{{num}} {{$store.state.num}}</h3>
<button @click="add">加2</button>
methods:
add() {
this.$store.commit("addNum",2);
},
第二种:
<h3>Right 组件{{num}} {{$store.state.num}}</h3>
<button @click="myAddNum">加2</button>
import { mapState, mapMutations } from "vuex";
methods: {
...mapMutations(["addNum"),
myAddNum() {
this.addNum(2); // 只加了这里
},
5.3 actions-发异步请求
所以vuex 规定:1. Mutation里必须是同步事务2. 所有异步事务交给Actions去执行
Action 本质上是 JavaScript 函数,专门用来处理 Vuex 中的异步操作
// commit 是专门用来触发moutations里的函数
// this.$store.commit('add')
// dispatch 是专门用来触发sctions里的函数//this.$store.dispatch("add");
<p>{{$store.state.num}}</p>
<button @click="add">+1</button>
methods: {
add() {
this.$store.dispatch("add");
},
},
main.js
actions里 调用commit触发触发mutations里的函数,显示快照
注意 actions里方法的第一个参数是store不是state
mutations:{
// mutations里的方法建议全大写
ADD_NUM(state,payload){
state.num++
}
},
actions:{
// 注意 actions里方法的第一个参数是store不是state
add(store){
// 千万不要在Mutations中异步代码的变更,devtools无法监视到数据变化
setTimeout(()=>{
// store.state.num++
// actions不显示快照
// 所以要调用commit触发触发mutations里的函数,显示快照
store.commit('ADD_NUM')
},3000)
}
}
简写
...mapActions(["add"]),
...mapActions方法 在methods 集体导入actions里的方法
methods: {
...mapActions(["add"]),
// 等价于下面
// add() {
// // dispatch 是专门用来触发actions里的函数
// this.$store.dispatch("add");
// },
},
5.4 getters 是vuex里的计算属性
计算属性的本质是属性 不是方法 是变量 只是写成了方法的样子
vue里computed 里的方法 实际是计算属性 可以后台打印看this 打印结果是属性my_num:3
和data里的变量的唯一的区别,它的值是通过别的变量计算得到的,如果别的数据发生变化,它也跟着变化
computed计算属性的变量 是来自于data的变量
<p>{{num}}</p> // 1
<p>{{my_num}}</p> // 6
<p>{{your_num()}}</p>
return {
// 普通属性 是固定的 不会变的属性
num: 1,
a: 3,
};
},
computed: {
// 计算属性 是计算得来的属性 不是函数方法 上面可以直接{{my_num}}显示
// my_num 是依据return的数值变化而变化的
my_num() {
return this.a+3;
},
methods: {
// 方法里的函数 上面显示需要带上() {{ your_num()}}
your_num() {
return 3;
},
解决办法 写一遍在getters里 共享计算属性 每个组件可以直接调用
Getters 是 Vuex 中的计算属性。当数据源发生变化时,Getters 的值会自动更新
getters的变量来自于state的变量
state的变量是有根的
getters的变量是没有根的 依赖于state的变量
...mapGetters(["isAllDone"]),
...mapGetters方法 在computed 集体导入acitions里的方法
汇总简写方法:
...mapState方法 在computed 集体导入vuex中的state里的数据
...mapGetters方法 在computed 集体导入acitions里的计算属性
...mapMutations方法 在methods 集体导入mutations里的同步方法
...mapActions方法 在methods 集体导入actions里的异步方法
5.5 modules模块化
new Vuex.Store({
state: {
num: 1
},
})
new Vuex.Store({
namespaced: true, // 开启命名空间变为局部
state: () => ({
num: 3,
}),
![](https://img-blog.csdnimg.cn/8cd4881d9e4847a3b8b9e172d47ddce0.png)
即state里的数据
![](https://img-blog.csdnimg.cn/2a7c24d663df45ecbb38f974992bc740.png)
第二步:注册模块
第三步:使用模块中的数据和方法
Modules – 命名空间 防止多个module之间变量名或方法名冲突
里面的total变量和changeTotal方法都一样,调用的时候成员名称冲突
namespaced(命名空间)
第一步:开启命名空间
第二步:在组件中使用带有命名空间的module
mapXXX(' 模块的注册名称 ', [ /* 要映射的成员名称 */ ])mapXXX(‘ 模块的注册名称 ’, {新的变量名: ’模块中的变量名’})
也可以把模块内state里所有的变量都map出来
![](https://img-blog.csdnimg.cn/97aedbe52ad043439b6bc219ee701c5e.png)