Vuex

Vuex

  官方说vuex是一个专为vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

  按我的理解就是,Vuex也是用来管理组建之间通信的。组件之间都是独立的,组件之间想实现通信,就要用到之前的文章提到的props选项,自定义事件,以及eventbus,前两种只适用于父子关系,eventbus可以适用所有的组件通信。但是据说不是很推荐,我想可能的原因是在大型项目中,到处引用一个eventbus代码可读性差、可能会命名冲突等,以及数据并不好进行管理。而Vuex就是解决这样的问题的,将组件需要共享的数据提出来,在一定的规则下管理这些数据,在大型项目中看起来就会仅仅有条。当然我也说了,是大型项目,一般的小项目还是用前三种方式去做吧,不要为了用vuex而用。

使用Vuex

  先创建一个实例,了解一下vuex:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vuex</title>
    <script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
    <script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.js"></script>
</head>
<body>
    <div id="app"></div>
</body>
<script>
    Vue.use(Vuex);
    let store = new Vuex.Store({
        // 存放组件之间共享的数据
        state: {
            name: 'myName'
        },
        // 显示更改state里的数据
        mutations: {

        },
        // 获取数据的方法
        getters: {

        },
        // 类似mutation,不是直接变更状态,而是提交mutation,还可以包含异步操作
        actions: {

        }
    });
    new Vue ({
        el: '#app',
        data() {
            return {
                name: 'null'
            };
        },
        store,
        mounted() {
            console.log(this.$store);
        } 
    });
</script>
</html>

  在创建vue实例前需使用vuex,也就是Vue.use(Vuex),使用Vuex.Store({})方法创建一个仓库,当Vue组件从store中读取state选项也就是状态,如果store中状态发生更新时,它会及时响应将数据发给其它组件,如果要直接改变store的状态,就使用使用mutations进行显式的更改。另外四个核心选项在代码中已经注释说明了。我们在控制台中打印了$store,来看看有哪些东西:

store

  一般情况下会在组件的计算属性中来获取state的数据,原因是计算属性会监控数据变化,数据改变就会响应。

// 在上面代码的html中加一个helloword的标签,在注册一个helloword的组件。就可以到浏览器中看到效果了。
Vue.component('helloword',{
        template:"<div>{{ name }}</div>",
        computed: {
            name() {
                return this.$store.state.name
            }
        },
         mounted() {
            console.log(this);
        }
    });

  我们可以在浏览器中看到保存在state中的数据,state就是存放共享数据的地方,getters就是store的计算属性,跟组件的计算属性类似,看一个例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vuex</title>
    <script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
    <script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.js"></script>
</head>
<body>
    <div id="app">
        <helloword></helloword>
    </div>
</body>
<script>
    Vue.use(Vuex);
    let store = new Vuex.Store({
        // 存放组件之间共享的数据
        state: {
            name: 'myName',
            age: 18
        },
        // 显示更改state里的数据
        mutations: {

        },
        // 获取数据的方法
        getters: {
            getAge(state) {
                return state.age;
            }
        },
        // 类似mutation,不是直接变更状态,而是提交mutation,还可以包含异步操作
        actions: {

        }
    });
    Vue.component('helloword',{
        template:"<div><div>{{ name }}</div><div>{{ age }}</div></div>",
        computed: {
            name() {
                return this.$store.state.name
            },
            age() {
                return this.$store.getters.getAge;
            }
        },
         mounted() {
            console.log(this);
        }
    });
    new Vue ({
        el: '#app',
        data() {
            return {
                name: 'null'
            };
        },
        store,
        mounted() {
            console.log(this.$store);
        } 
    });
</script>
</html>

  通过在store的getters中定义getAge方法,就可以得到age了。

  mutations:在vuex中实际改变状态state的唯一方法就是通过commit一个mutation,mutations内的函数接收state作为第一参数,接收payload(载荷)作为第二参数,这个就是记录使用该函数的信息,就是提交了什么更改了什么之类的,所以这个东西真的跟git是比较相似的。例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vuex</title>
    <script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
    <script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.js"></script>
</head>
<body>
    <div id="app">
        <helloword></helloword>
    </div>
</body>
<script>
    Vue.use(Vuex);
    let store = new Vuex.Store({
        // 存放组件之间共享的数据
        state: {
            name: 'myName',
            age: 18
        },
        // 显示更改state里的数据
        mutations: {
            changeAge(state, a) {
                state.age += a;
                console.log(state.age);
            }
        },
        // 获取数据的方法
        getters: {
            getAge(state) {
                return state.age;
            }
        },
        // 类似mutation,不是直接变更状态,而是提交mutation,还可以包含异步操作
        actions: {

        }
    });
    Vue.component('helloword',{
        template:"<div><div>{{ name }}</div><div @click='changAge'>{{ age }}</div></div>",
        computed: {
            name() {
                return this.$store.state.name
            },
            age() {
                return this.$store.getters.getAge;
            }
        },
        mounted() {
            console.log(this);
        },
        methods: {
            changAge() {
                // 组件中提交
                this.$store.commit('changeAge', 12);
            }
        }
    });
    new Vue ({
        el: '#app',
        data() {
            return {
                name: 'null'
            };
        },
        store,
        mounted() {
            console.log(this.$store);
        } 
    });
</script>
</html>

  当我们每次点击年龄的时候就会调用组件changeAge的方法,然后在这个方法中我们显示的提交了更改state中的age。当然,mutations只能处理同步方法。所以actions应运而生,js中涉及很多回调,涉及很多异步操作。actions不是直接更改state而是通过提交mutation来更改数据,action可以包含任意的异步操作,ajax、settimeout等。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vuex</title>
    <script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
    <script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.js"></script>
</head>
<body>
    <div id="app">
        <helloword></helloword>
    </div>
</body>
<script>
    Vue.use(Vuex);
    let store = new Vuex.Store({
        // 存放组件之间共享的数据
        state: {
            name: 'myName',
            age: 18
        },
        // 显示更改state里的数据
        mutations: {
            changeAge(state, a) {
                state.age += a;
                console.log(state.age);
            },
            asyncChange(state, data) {
                state.name += data;
                console.log(state.name); 
            }
        },
        // 获取数据的方法
        getters: {
            getAge(state) {
                return state.age;
            }
        },
        // 类似mutation,不是直接变更状态,而是提交mutation,还可以包含异步操作
        actions: {
            commitChangeName(context, value) {
                setTimeout(() => {
                    context.commit('asyncChange', value);
                },1000);
            }
        }
    });
    Vue.component('helloword',{
        template:`
        <div>
            <div @click='alertName'>{{ name }}</div>
            <div @click='changAge'>{{ age }}</div>
        </div>`,
        computed: {
            name() {
                return this.$store.state.name
            },
            age() {
                return this.$store.getters.getAge;
            }
        },
        mounted() {
            console.log(this);
        },
        methods: {
            changAge() {
                // 组件中提交
                this.$store.commit('changeAge', 12);
            },
            alertName() {
                this.$store.dispatch('commitChangeName', ' is wangx.');
            }
        }
    });
    new Vue ({
        el: '#app',
        data() {
            return {
                name: 'null'
            };
        },
        store,
        mounted() {
            console.log(this.$store);
        } 
    });
</script>
</html>

  上面的代码就是一个actions的例子,在组件中注册一个方法,alertName,点击myName之后,我们派发事件,触发actions中的commitChangeName,该方法中有一个异步操作,等待1秒后会提交一个mutation,更改state中的name。我们在浏览器中就可以看到效果啦。这就是actions的一个更改state的流程。

总结

  这是我看了Vuex的官网学习了一下以及网上看的教程,大概了解了如何使用vuex。当然还没有用到项目中去,项目中用也不是不可以,我觉得如果项目比较小,可管理的数据比较少,我们直接用其他的通信方式处理就好了。state就是存放数据的仓库,mutation就是用来显示的更改仓库中的数据,就像仓库管理员一样。getters就像出货的工人,只管往外取,不管如何往仓库装货,当然一般情况,仓库的工人都是需要搬进搬出的。另外actions就像中间人,告诉你管理员怎么改数据,管理员去改。大概理解的vuex就是这样,后续实际使用遇到坑了再来填。