目 录CONTENT

文章目录

vuex全局状态管理

Administrator
2021-11-18 / 0 评论 / 0 点赞 / 5345 阅读 / 14392 字

vuex全局状态管理

一、什么需要全局状态

image-20211118084140393

如上图所示,对于上面的页在页面结构,如果App.vue里面的数据需要传递到子级组件晚们可以使用自定义属性去传递

App.vue代码

<login user-name='张三'></login>
<register user-name='张三'></register>

对于这样的父子结构,我们使用这一种自定义的属性传递是非常方便的

但是在大型的项目里面,总会有一些复杂的布局,如下图所示

image-20211118084427149

上图中我们可以看到login.vue的组件里面有一个user-item.vue的组件,这个组件的内部有一个register.vue组件,它有一个数据nickName想传递给register.vue使用,怎么办呢?这个时候以目前技术来说我们不好实现

二、vue的全局状态管理工具

image-20211118084852676

这种东西在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>
image-20211118085743400

如上图所示,如果我们想把two这个组件内部的数据nickName 传递给three这个组件,这样非常麻烦

vuex的创建

const store = new Vuex.Store({
    state:{},
    mutations:{},
    actions:{},
    getters:{},
    plugins:[]
});

new Vue({
    el:"#app",
    store
})

这个store就是全局区域

image-20211118091010008

当一个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的内部,状态的改变量个完整的运行流程图

vuex图解

上面就是一个vue的运行原理图,我把它理解为下面的情况

image-20211118093256358

在上面的流程图里面,我们可以看到,如果要改变某一个状态,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的使用有下面几种方式

  1. state

    组件内部

    <h2>
        {{$store.state.属性名}}
    </h2>
    
  2. getters

    组件内部

    <h2>
        {{$store.getters.属性名}}
    </h2>
    
  3. actions

    组件内部

    this.$store.dispatch("action名称",参数);
    

上面这些都是最原始的方法,其实因为vuex的使用是非常繁琐的,所以vuex的内部提供了另一种快速操作的方法

  1. mapState用于快速获取状态state
  2. mapGetters用于快速获取getters计算属性
  3. 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
0
vue

评论区