一、Vuex
Vuex是一个专为Vue.js应用程序开发的状态管理模式。
官网:https://next.vuex.vuejs.org/
主要功能:
- Vuex可以实现Vue不同组件之间的状态共享(解决了不同组件之间的数据共享)
- 可以实现组件里面的数据持久化
Vuex的几个核心概念
- State 主要用于定义数据
- Getters 与前面的计算属性类似,用于vuex中计算属性
- Mutations 主要用于定义方法,改变state中的数据
- Actions 主要用于执行Mutations的方法,用于异步操作
- Modules
二、Vuex的基本使用
-
安装依赖
npm install vuex@next --save # 或者 yarn add vuex@next --save
-
src目录下新建一个Vuex的目录,Vuex目录里面新建一个store.js
import {createStore} from 'vuex';
const store=createStore({
state(){
// 定义数据
return{
count:1
}
},
mutations:{
// 定义方法
incCount(state){
state.count++;
}
}
});
export default store;
-
main.ts挂载store.js
import {createApp} from 'vue' import App from '@/App.vue' import router from "@/router";// 引入router import store from "@/Vuex/store.js"; const app = createApp(App); app.use(router);//挂载使用router app.use(store);// 挂载Vuex的store app.mount('#app')
三、Vuex中的State
-
第一种获取State的方法(不推荐)
用到的组件里面引用store,然后计算属性里面获取 (单页面组件引用)
computed:{ count(){ return store.state.count } }
-
第二种获取State的方法
由于全局配置了Vuex app.use(store)。所以直接可以通过下面的方法获取store里面的值。
computed:{ count(){ return this.$store.state.count } }
获取store中的list
<template> <ul> <li v-for="(item,index) in $store.state.list" :key="index"> {{item}} </li> </ul> </template>
-
第三中获取State的方法-通过mapState助手
调用的组件中引入mapState
import {mapState} from "vuex"
-
方法1:store中的变量与组件中的变量名称不一致,使用箭头函数做映射
-
方法2:store中的变量与组件中的变量名一样可以直接这样使用
computed: { // 方法1 ...mapState({ thisCount: (state) => state.count, thisBanner: (state) => state.banner, thisList: (state) => state.list, }), //方法2 ...mapState(["count","banner","list"]) }
在模板中调用:
<template> <h3>mapState获取store中的数据(方法1)</h3> thisCount:{{ thisCount }} <br> thisBanner:{{ thisBanner }} <br> <ul> <li v-for="(item,index) in thisList" :key="index"> {{ item }} </li> </ul> <hr> <h3>mapState获取store中的数据(方法2)</h3> count:{{ count }} <br> banner:{{ banner }} <br> <ul> <li v-for="(item,index) in list" :key="index"> {{ item }} </li> </ul> </template>
-
四、Vuex中的Getter
-
定义Getter
const store = createStore({ state() { // 数据 return { count: 1, banner: "zws", list: ["文件", "编辑", "视图"], msg: "你好store" } }, mutations: { // 方法,可以改变state里面的数据 incCount(state) { state.count++; }, setCount(state, num) { state.count += num; }, setBanner(state) { state.banner = "改变后的banner" } }, getters: { revMsg(state) { return state.msg.split("").reverse().join(""); }, num(state) { return state.count + 10; } } });
-
访问Getter的方法
-
方法一:Getter会暴露为store.getter对象,你可以以属性的形式访问这些值:
<template> {{$store.getters.num}} </template>
-
方法二:使用计算属性
computed:{ count(){ return this.$store.state.count }, banner(){ return this.$store.state.banner }, revMsg(){ return this.$store.getters.revMsg; }, num(){ return this.$store.getters.num; } }
-
方法三:通过mapGetters辅助函数
import {mapState,mapGetters} from "vuex"
computed: { // 方法1 ...mapState({ thisCount: (state) => state.count, thisBanner: (state) => state.banner, thisList: (state) => state.list, }), //方法2 ...mapState(["count","banner","list"]), // 使用对象展开运算符...mapGetters混入computed处对象中 // 方法1 ...mapGetters([ "num","revMsg" ]), // 方法2 // 给store中的getters取个别名 ...mapGetters({ thisMsg: "revMsg", thisNum: "num", }), }
template中使用
<template> <h3>mapGetters获取store中的getters(方法1)</h3> revMsg:{{revMsg}} <br> num:{{num}} <br> <h3>mapGetters获取store中的getters(方法2)</h3> revMsg:{{thisMsg}} <br> num:{{thisNum}} </template>
-
五、Vuex中的Mutations
更改Vuex的store中的状态唯一的方法时提交mutation。Vuex中的mutation非常类似于事件:每个mutation都有一个字符串类型的事件类型(type)和一个回调函数(handler)。这个回到函数就是我们实际进行状态更改的地方,并且它会接收state作为第一个参数。
-
定义Mutations触发Mutations里面的方法
const store=createStore({ state(){ return{ count:1 } }, mutations:{ incCount(state){ // mutate state state.count++; } } });
触发mutations里面的方法:
this.$store.commit('incCount')
-
执行方法传入参数:
const store=createStore({ state(){ // 数据 return{ count:1, myname:"zws" } }, mutations:{ // 方法,可以改变state里面的数据 incCount(state){ state.count++; }, setCount(state,num){ state.count+=num; }, setMyName(state){ state.myname="改变后的zws" } } });
触发方法:
this.$store.commit("setCount",15);
六、Vuex中的Actions
-
store.js中定义Actions
const store = createStore({ state() { // 数据 return { count: 1, banner: "zws", list: ["文件", "编辑", "视图"], msg: "你好store" } }, mutations: { // 方法,可以改变state里面的数据 incCount(state) { state.count++; }, setCount(state, num) { state.count += num; }, setBanner(state, msg) { state.banner = "改变后的banner" + msg; } }, getters: { revMsg(state) { return state.msg.split("").reverse().join(""); }, num(state) { return state.count + 10; } }, actions: { // 主要用于执行Mutations里面的方法,异步操作放在这里 inCount(context) { // 执行mutations里面的incCount方法 context.commit("incCount"); }, incSetBanner(context,msg) { setTimeout(() => { context.commit("setBanner", msg); }, 1000); }, // 另一种写法 /*incSetBanner({commit},msg) { setTimeout(() => { commit("setBanner", msg); }, 1000); },*/ } });
-
触发Actions中的方法
store.dispatch("inCount"); store.dispatch("incSetBanner","zws");
乍一眼看上去感觉多此一举,我们直接分发mutations岂不是更方便?实际上并非如此,还记得mutations必须同步执行这个限制么?Actions就不受约束~!我们可以在actions内部执行异步操作
七、Vuex中的Modules
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿。
为了解决以上问题,Vuex允许我们将store分割成模块(Modules)。每个模块拥有自己的state,mutations,actions,getters,甚至是嵌套子模块——从上至下进行同样的方式分割:
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> `moduleA`'s state
store.state.b // -> `moduleB`'s state
示例:
在Vuex目录新建userStore.js
let userStore = {
state() {
// 数据
return {
count: 1,
banner: "zws",
msg: "你好store"
}
},
mutations: {
// 方法,可以改变state里面的数据
incCount(state) {
state.count++;
},
setCount(state, num) {
state.count += num;
},
setBanner(state, msg) {
state.banner = "改变后的banner" + msg;
}
},
getters: {
revMsg(state) {
return state.msg.split("").reverse().join("");
},
num(state) {
return state.count + 10;
}
},
actions: {
// 主要用于执行Mutations里面的方法,异步操作放在这里
inCount(context) {
// 执行mutations里面的incCount方法
context.commit("incCount");
},
incSetBanner(context, msg) {
setTimeout(() => {
context.commit("setBanner", msg);
}, 1000);
},
}
}
export default userStore;
在Vuex目录新建newsStore.js
let newsStore = {
state() {
// 数据
return {
list: ["新闻1", "新闻2", "新闻3"],
count: 100
}
},
mutations: {
incCount(state) {
state.count++;
}
}
}
export default newsStore;
改造store.js
import {createStore} from 'vuex';
import userStore from '@/Vuex/userStore';
import newsStore from "@/Vuex/newsStore";
const store = createStore({
modules:{
"user":userStore,
"news":newsStore
}
});
export default store;
在User.vue组件中使用userStore与newsStore的state数据与调用mutations里面的方法
<template>
<div>
<h1>User组件</h1>
获取userStore里面的count:{{$store.state.user.count}}
<br>
获取newsStore里面的count:{{$store.state.news.count}}
获取newsStore里面的list:
<ul>
<li v-for="(item,index) in list" :key="index">
{{item}}
</li>
</ul>
<br>
<br>
<button @click="incCount">调用mutations里面的方法</button>
</div>
</template>
<script>
import {defineComponent} from "vue";
export default defineComponent({
setup() {
return {}
},
computed:{
list(){
return this.$store.state.news.list;
}
},
methods:{
incCount(){
// 调用mutations里面的方法
// 广播:userStore与newsStore里面的incCount都会执行
this.$store.commit("incCount");
}
}
});
</script>
注意:如果多个store模块中定义有相同的方法名,调用的时候,都会被调用