vuex全局状态管理
一、什么需要全局状态
如上图所示,对于上面的页在页面结构,如果App.vue
里面的数据需要传递到子级组件晚们可以使用自定义属性去传递
App.vue代码
<login user-name='张三'></login>
<register user-name='张三'></register>
对于这样的父子结构,我们使用这一种自定义的属性传递是非常方便的
但是在大型的项目里面,总会有一些复杂的布局,如下图所示
上图中我们可以看到login.vue
的组件里面有一个user-item.vue
的组件,这个组件的内部有一个register.vue
组件,它有一个数据nickName
想传递给register.vue
使用,怎么办呢?这个时候以目前技术来说我们不好实现
二、vue的全局状态管理工具
这种东西在vue里面叫全局状态管理,它有一个专门包去实现,叫vuex
vue的全局状态管理工具叫vuex,它内部有一套完整的状态管理机制,可以轻松的实现全局状态渲染组件,改变等操作
三、vuex的安装
$ npm install vuex
$ yarn add vuex
它的安装非常简单,它可以在脚手里面使用,也可以在普通的页面上面使用,只是在webpack的脚手架里面使用的时候会有更多的功能
四、vuex的内部原理
在没有vuex的情况下
<body>
<div id="app">
<one>
<two></two>
</one>
<three></three>
</div>
<template id="temp1">
<div class="box">
<h2>我是第一个组件</h2>
<slot></slot>
</div>
</template>
<template id="temp2">
<div class="box">
<h2>我是第二个组件</h2>
<h2>{{nickName}}</h2>
<slot></slot>
</div>
</template>
<template id="temp3">
<div class="box">
<h2>我是第三个组件</h2>
<slot></slot>
</div>
</template>
</body>
<script src="./js/vue.js"></script>
<script>
Vue.component("one",{
template:"#temp1"
});
Vue.component("two",{
template:"#temp2",
data(){
return {
nickName:"张三"
}
}
});
Vue.component("three",{
template:"#temp3"
});
new Vue({
el:"#app"
})
</script>
如上图所示,如果我们想把two
这个组件内部的数据nickName
传递给three
这个组件,这样非常麻烦
vuex的创建
const store = new Vuex.Store({
state:{},
mutations:{},
actions:{},
getters:{},
plugins:[]
});
new Vue({
el:"#app",
store
})
这个store就是全局区域
当一个vue加载了vuex
的store以后,在内部就会有一个$store
的属性,这个属性就是用于操控全局状态的
1. state状态
在vuex内部,这个state
是用于存储状态的(通俗一点就是用于存储全局变量的),相当于组件内部的data
属性
state:{
nickName:"小珊子"
}
如果在某一个组件里面可以下面的方式使用全局状态
<h3>{{$store.state.nickName}}</h3>
2. mutations转变
vuex的状态state相当于组件内部的data,竟然是变量就可以改变,所以如果改变vuex
内部的state的数据呢
Vue.component("two", {
template: "#temp2",
methods:{
changeNickName(){
//这种写法就是不对的
this.$store.state.nickName = "帅哥哥";
}
}
});
在上面的代码当中,如果直接 这么改变是不对的,因为state
是全局的,在所有的地方都可以改变,在某些特殊的时候就会出现冲突的情况,如a组件要改变nickName,b组件也要改变nickName,那么到底先执行哪一步操作呢
vuex的内部,状态的改变量个完整的运行流程图
上面就是一个vue的运行原理图,我把它理解为下面的情况
在上面的流程图里面,我们可以看到,如果要改变某一个状态,components
里面是不能够直接改变的,必须mutations
去改变
// 锦衣卫
mutations:{
setNickName(state,nickName){
state.nickName = nickName;
}
},
mutations的方法当中,这个方法名可以随便到,方法所接收到的第一个参数是 vuex系统自动给你注入的state
3. actions方法
同理,如果muations
想做出相应的改变,它也要有别人让它做改变,这个时候就要收actions
提交一个任务过去
// 太监
actions:{
setNickName({commit},nickName){
commit("setNickName",nickName)
}
}
actions里面的方法名也可以随便取,这个方法所接收到的第一个参数要解构出一个
commit
的方法,提交mutations
我们一旦完成上面的操作过程以后,如果们需要改变vuex
的状态,则应该使用下面的方法
this.$store.dispatch("setNickName","我是nickName更新的值");
4.getter获取
这个相当于vuex内部的计算属性,如下所示
const store = new Vuex.Store({
// 大臣
state: {
nickName: "小珊子",
age: 22
},
//相当于组件内部地计算属性
getters: {
adult(state) {
return state.age >= 18 ? "成年" : "未成年"
}
}
})
后面在使用的时候直接 使用
<h2>
{{$store.getters.adult}}
</h2>
getters
本身是一个方法,返回一个值,这个方法第一个参数是vuex系统内部注入的state
状态
完整代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vuex</title>
<style>
.box {
border: 1px solid black;
margin: 5px;
padding: 5px;
}
</style>
</head>
<body>
<div id="app">
<one>
<two></two>
</one>
<three></three>
</div>
<template id="temp1">
<div class="box">
<h2>我是第一个组件</h2>
<h3>{{$store.state.nickName}}</h3>
<h2>年龄:{{$store.state.age}}</h2>
<slot></slot>
</div>
</template>
<template id="temp2">
<div class="box">
<h2>我是第二个组件</h2>
<h3>{{$store.state.nickName}}</h3>
<h2>年龄:{{$store.state.age}}</h2>
<button type="button" @click="changeNickName">我要必变nickName</button>
<slot></slot>
</div>
</template>
<template id="temp3">
<div class="box">
<h2>我是第三个组件</h2>
<h3>{{$store.state.nickName}}</h3>
<h2>年龄:{{$store.state.age}}</h2>
<h2>{{$store.getters.adult}}</h2>
<slot></slot>
</div>
</template>
</body>
<script src="./js/vue.js"></script>
<script src="./js/vuex.js"></script>
<script>
Vue.component("one", {
template: "#temp1"
});
Vue.component("two", {
template: "#temp2",
methods: {
changeNickName() {
this.$store.dispatch("setNickName", "我是通过vuex改变的值");
}
}
});
Vue.component("three", {
template: "#temp3"
});
const store = new Vuex.Store({
// 大臣
state: {
nickName: "小珊子",
age: 22
},
// 锦衣卫
mutations: {
setNickName(state, nickName) {
state.nickName = nickName;
}
},
// 太监
actions: {
setNickName({
commit
}, nickName) {
commit("setNickName", nickName)
}
},
//相当于组件内部地计算属性
getters: {
adult(state) {
return state.age >= 18 ? "成年" : "未成年"
}
}
})
const app = new Vue({
el: "#app",
store
})
</script>
</html>
五、vuex中的mapGetter等使用
在之前上面讲到,我们vuex的使用有下面几种方式
-
state
组件内部
<h2> {{$store.state.属性名}} </h2>
-
getters
组件内部
<h2> {{$store.getters.属性名}} </h2>
-
actions
组件内部
this.$store.dispatch("action名称",参数);
上面这些都是最原始的方法,其实因为vuex的使用是非常繁琐的,所以vuex的内部提供了另一种快速操作的方法
mapState
用于快速获取状态state
mapGetters
用于快速获取getters
计算属性mapActions
用于快速获取actions
方法
这三个东西在普通模式下面使用不了,必须在ESModule或webpack下面使用,现在的vue脚手架项目都是基于ESModule的webpack项目,所以我们是可以直接去使用的
其实在这里,标哥单独给你们讲一下,我们现的vue可以在浏览器模块 webapck的ESModule环境,所以我们现在可以先在浏览器的环境下面来学习上面的三个方法
<script src="./js/xxx.js" type="text/javascript"></script>
现在在新版的浏览器里面,可以使用下面的试试
<script src="./js/xxx.js" type="module"></script>
正是因为有了这种新版的写法,所以我们可以在浏览器的环境下面模拟 webpack的ESModule来开发学习
完整代码案例
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vuex高级用法</title>
<style>
.box {
border: 1px solid black;
margin: 5px;
padding: 5px;
}
</style>
</head>
<body>
<div id="app">
<one>
<two></two>
</one>
<three></three>
</div>
<template id="temp1">
<div class="box">
<h2>第一个组件</h2>
<h2>昵称:{{nickName}}</h2>
<slot></slot>
</div>
</template>
<template id="temp2">
<div class="box">
<h2>第二个组件</h2>
<h2>年龄:{{age}}</h2>
<button type="button" @click="changeNickName">我要改变昵称</button>
<slot></slot>
</div>
</template>
<template id="temp3">
<div class="box">
<h2>第三个组件</h2>
<h2>昵称:{{nickName}}</h2>
<h2>年龄:{{age}}</h2>
<h2>状态:{{adult}}</h2>
<slot></slot>
</div>
</template>
</body>
<script type="module">
import Vue from "./js/vue.esm.browser.js";
import Vuex,{mapState,mapGetters,mapActions} from "./js/vuex.esm.browser.js";
//这里一定要注意,因为我们在模块脚手架的环境
Vue.use(Vuex);
Vue.component("one",{
template:"#temp1",
computed:{
...mapState(["nickName"])
}
});
Vue.component("two",{
template:"#temp2",
computed:{
...mapState(["age"])
},
methods:{
...mapActions(["setNickName"]),
changeNickName(){
// this.$store.dispatch("setNickName","我要改你的值");
this.setNickName("哈哈,我现在要改变你的值 ,就快多了");
}
}
});
Vue.component("three",{
template:"#temp3",
computed:{
...mapState(["nickName","age"]),
...mapGetters(["adult"])
}
});
const store = new Vuex.Store({
state:{
nickName:"张三丰",
age:22
},
mutations:{
setNickName(state,nickName){
state.nickName = nickName;
}
},
actions:{
setNickName({commit},nickName){
commit("setNickName",nickName)
}
},
getters:{
adult(state){
return state.age>18?"成年":"小屁孩"
}
}
})
new Vue({
el:"#app",
store
})
</script>
</html>
六、vuex状态持久化
npm install vuex-persistedstate --save
评论区