zoukankan      html  css  js  c++  java
  • Vue学习笔记(十一) Vuex

    1、介绍

    Vuex 是一个为 Vue 应用程序开发的状态管理模式,它用集中式存储来管理应用所有组件的状态

    简单来说,它的作用就是把所有组件的共享状态抽取出来,以一个全局单例的模式进行管理

    我们可以把 Vuex 理解成一个 store,里面存储着所有组件共享的 state(数据)和 mutations(操作)

    这里还是先附上官方文档的链接:https://vuex.vuejs.org/zh/,有兴趣的朋友可以去看看

    2、安装

    (1)通过 CDN 引用

    <script src="https://unpkg.com/vue"></script>
    <script src="https://unpkg.com/vuex"></script>
    

    (2)通过 NPM 安装与使用

    • 安装
    > npm install vuex
    
    • 使用

    在项目中需要通过 Vue.use() 明确安装 Vuex

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    

    3、State

    Vuex 中的 state 用于集中存储数据,当我们需要访问 state 时,可以先将其映射为计算属性

    由于 state 是响应式的,所以当 state 发生变化时,它会重新求取计算属性,并自动更新相应的 DOM

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Demo</title>
        <script src="https://unpkg.com/vue"></script>
        <script src="https://unpkg.com/vuex"></script>
    </head>
    
    <body>
        <div id="app">
            <my-counter></my-counter>
        </div>
    
        <script>
            // 1、定义 store
            const store = new Vuex.Store({
                state: { // 定义 state
                    count: 0
                }
            })
    
            // 2、定义组件
            const Counter = {
                template: `
                    <div>
                        <p>{{ count }}</p>
                    </div>
                `,
                // 如果需要访问 state,可以在计算属性中通过 this.$store.state 返回数据
                computed: {
                    count() {
                        return this.$store.state.count
                    }
                }
            }
    
            // 3、创建并挂载根实例
            const app = new Vue({
                store, // 注入 store
                components: {
                   'my-counter': Counter 
                }
            }).$mount('#app')
        </script>
    </body>
    
    </html>
    

    现在假设我们需要在一个组件中使用多个 state,如果为每个状态都写一条语句将其映射为计算属性未免太过繁琐

    所以 Vuex 提供 mapState() 辅助函数能够帮助我们完成这些工作

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Demo</title>
        <script src="https://unpkg.com/vue"></script>
        <script src="https://unpkg.com/vuex"></script>
    </head>
    
    <body>
        <div id="app">
            <my-counter></my-counter>
        </div>
    
        <script>
            const store = new Vuex.Store({
                state: {
                    counter1: 0,
                    counter2: 10,
                    counter3: 100
                }
            })
    
            const Counter = {
                template: `
                    <div>
                        <p>couter1: {{ counter1 }}</p>
                        <p>couter2: {{ counter2 }}</p>
                        <p>couter3: {{ counter3 }}</p>
                    </div>
                `,
                data: function () {
                    return {
                        localCounter: 1
                    }
                },
                computed: {
                    // mapState() 返回一个对象,使用对象展开运算符将其混入 computed 对象
                    ...Vuex.mapState({
                        // 使用箭头函数,可以简化代码
                        counter1: state => state.counter1,
    
                        // 使用字符串 'counter2',等价于 `state => state.counter2`
                        counter2: 'counter2',
    
                        // 使用常规函数,可使用 `this` 以获取局部状态
                        counter3 (state) {
                            return state.counter3 + this.localCounter
                        }
                    })
                }
            }
    
            const app = new Vue({
                store,
                components: {
                    'my-counter': Counter
                }
            }).$mount('#app')
        </script>
    </body>
    
    </html>
    

    5、Getter

    Vuex 中的 getter 用于管理派生出来的状态

    它就相当于计算属性一样,会被缓存起来,当依赖发生改变时才会重新计算

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Demo</title>
        <script src="https://unpkg.com/vue"></script>
        <script src="https://unpkg.com/vuex"></script>
    </head>
    
    <body>
        <div id="app">
            <my-todo></my-todo>
        </div>
    
        <script>
            const store = new Vuex.Store({
                state: {
                    todos: [
                        { id: 1, text: 'Say Hello', done: true},
                        { id: 2, text: 'Say Goodbye', done: false}
                    ]
                },
                getters: { // 定义 getters
                    // 其接受 state 作为第一个参数
                    doneTodos: state => {
                        return state.todos.filter(todo => todo.done)
                    },
                    // 其接受 getters 作为第二个参数
                    doneTodosCount: (state, getters) => {
                        return getters.doneTodos.length
                    }
                }
            })
    
            const Todo = {
                template: `
                    <div>
                        <p>{{ doneTodosCount }} task(s) done</p>
                        <ul><li v-for="item in doneTodos">{{ item.text }}</li></ul>
                    </div>
                `,
                computed: {
    				doneTodos () {
                        return this.$store.getters.doneTodos
                    },
                    doneTodosCount () {
                        return this.$store.getters.doneTodosCount
                    }
                }
            }
    
            const app = new Vue({
                store,
                components: {
                   'my-todo': Todo
                }
            }).$mount('#app')
        </script>
    </body>
    
    </html>
    

    和 state 一样,getters 也有一个名为 mapGetters() 的辅助函数将其映射为计算属性

    computed: {
        ...mapGetters([
          'doneTodos',
          'doneTodosCount'
        ])
    }
    

    如果要给 getter 重命名,可以用对象形式

    computed: {
        ...mapGetters({
          doneTodosAlias: 'doneTodos',
          doneTodosCountAlias: 'doneTodosCount'
        })
    }
    

    5、Mutation

    上面我们讲了怎么访问 state,下面我们来看看怎么修改 state,改变状态的唯一方法是提交 mutation

    这里,请记住一条重要的规则:mutation 必须是同步函数

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Demo</title>
        <script src="https://unpkg.com/vue"></script>
        <script src="https://unpkg.com/vuex"></script>
    </head>
    
    <body>
        <div id="app">
            <my-counter></my-counter>
        </div>
    
        <script>
            const store = new Vuex.Store({
                state: {
                    count: 0
                },
                mutations: { // 定义 mutations
                    // 传入的第一个参数是 state
                    increment(state) {
                        state.count += 1
                    },
                    // 传入的第二个参数是 payload,可以提供额外的信息
                    incrementN(state, payload) {
                        state.count += payload.amount
                    }
                }
            })
    
            const Counter = {
                template: `
                    <div>
                        <p>{{ count }}</p>
                        <button @click="increment"> 加 1 </button>
                        <button @click="incrementN"> 加 10 </button>
                    </div>
                `,
                // 如果需要访问 state,可以在计算属性中通过 store.state 返回数据
                computed: {
                    count() {
                        return store.state.count
                    }
                },
                // 如果需要修改 state,可以通过 store.commit() 提交 mutation
                methods: {
                    increment() {
                        store.commit('increment')
                    },
                    incrementN() { // 以对象的形式给 commit() 传入 payload
                        store.commit('incrementN', {
                            amount: 10
                        })
                    }
                }
            }
    
            const app = new Vue({
                store,
                components: {
                    'my-counter': Counter
                }
            }).$mount('#app')
        </script>
    </body>
    
    </html>
    

    当然,我们也可以使用 mapMutations() 辅助函数将 mutation 映射为 methods

    methods: {
        ...mapMutations([
            'increment',
            'incrementN'
        ])
    }
    

    也同样可以使用对象形式支持重命名

    methods: {
        ...mapMutations({
            add: 'increment',
            addN: 'incrementN'
        })
    }
    

    6、Action

    还记得上面我们说过 mutation 只能是同步函数,若需要使用异步操作,则可以通过分发 action

    action 内部可以包含异步逻辑,它做的工作是提交 mutation,而不是直接改变状态

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Demo</title>
        <script src="https://unpkg.com/vue"></script>
        <script src="https://unpkg.com/vuex"></script>
    </head>
    
    <body>
        <div id="app">
            <my-counter></my-counter>
        </div>
    
        <script>
            const store = new Vuex.Store({
                state: {
                    count: 0
                },
                mutations: {
                    increment(state) {
                        state.count += 1
                    },
                    incrementN(state, payload) {
                        state.count += payload.amount
                    }
                },
                actions: { //定义 actions
                    // 该方法接受一个与 store 实例具有相同属性和方法的对象作为参数
                    // 我们可以调用 context.commit() 提交 mutation
                    // 也可以通过 context.state 和 context.getters 访问 state 和 getters
                    incrementAsync(context) {
                        setTimeout(() => {
                            context.commit('increment')
                        }, 1000)
                    },
                    // 和 mutations 一样,也可以传入第二个参数 payload
                    incrementNAsync(context, payload) {
                        setTimeout(() => {
                            context.commit('incrementN', payload)
                        }, 1000)
                    }
                }
            })
    
            const Counter = {
                template: `
                    <div>
                        <p>{{ count }}</p>
                        <button @click="increment"> 同步加 1 </button>
                        <button @click="incrementN"> 同步加 10 </button>
                        <button @click="incrementAsync"> 异步加 1 </button>
                        <button @click="incrementNAsync"> 异步加 10 </button>
                    </div>
                `,
                computed: {
                    count() {
                        return store.state.count
                    }
                },
                methods: {
                    // 通过 store.commit() 提交 mutation
                    increment() {
                        store.commit('increment')
                    },
                    incrementN() { // 以对象的形式给 commit() 传入 payload
                        store.commit('incrementN', {
                            amount: 10
                        })
                    },
                    // 通过 store.dispatch() 分发 action
                    incrementAsync() {
                        store.dispatch('incrementAsync')
                    },
                    incrementNAsync() { // 以对象的形式给 dispatch() 传入 payload
                        store.dispatch('incrementNAsync', {
                            amount: 10
                        })
                    }
                }
            }
    
            const app = new Vue({
                store,
                components: {
                    'my-counter': Counter
                }
            }).$mount('#app')
        </script>
    </body>
    
    </html>
    

    如果需要处理更复杂的异步逻辑,我们也可以使用 Promise 和 async/await

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Demo</title>
        <script src="https://unpkg.com/vue"></script>
        <script src="https://unpkg.com/vuex"></script>
    </head>
    
    <body>
        <div id="app">
            <my-counter></my-counter>
        </div>
    
        <script>
            const store = new Vuex.Store({
                state: {
                    count: 0
                },
                mutations: {
                    add(state) {
                        state.count += 10
                    },
                    multiply(state) {
                        state.count *= 10
                    }
                },
                actions: {
                    addAsync(context) {
                        setTimeout(() => {
                            context.commit('add')
                        }, 1000)
                    },
                    multiplyAsync(context) {
                        setTimeout(() => {
                            context.commit('multiply')
                        }, 1000)
                    },
                    // 只允许使用异步函数 addAsync 和 multiplyAsync,实现先乘后加
                    // 使用 async/await
                    async multiplyBeforeAdd(context) {
                        await context.dispatch('multiplyAsync')
                        context.dispatch('addAsync')
                    },
                    // 只允许使用异步函数 addAsync 和 multiplyAsync,实现先加后乘
                    // 使用 async/await
                    async addBeforeMultiply(context) {
                        await context.dispatch('addAsync')
                        context.dispatch('multiplyAsync')
                    }
                }
            })
    
            const Counter = {
                template: `
                    <div>
                        <p>{{ count }}</p>
                        <button @click="done"> 乘10,加10,加10,乘10 </button>
                    </div>
                `,
                computed: {
                    count() {
                        return store.state.count
                    }
                },
                methods: {
                    // 先完成先乘后加,再完成先加后乘
                    done() {
                        store.dispatch('multiplyBeforeAdd').then(() => {
                            store.dispatch('addBeforeMultiply')
                        })
                    }
                }
            }
    
            const app = new Vue({
                store,
                components: {
                    'my-counter': Counter
                }
            }).$mount('#app')
        </script>
    </body>
    
    </html>
    

    【 阅读更多 Vue 系列文章,请看 Vue学习笔记

    版权声明:本博客属于个人维护博客,未经博主允许不得转载其中文章。
  • 相关阅读:
    实例:如何设计一款好的Metro UI应用
    给用户和开发者最佳的.Net框架部署方案
    软件测试对嵌入式系统的影响
    如何创造出优秀的用户体验?
    Xamarin:使用C#移植Android操作系统
    WCF数据服务5.0 RTM发布
    演进式数据库建模
    zsh 命令行编辑技巧三则
    Oracle与MySQL的几点区别
    window下mysql表的修复
  • 原文地址:https://www.cnblogs.com/wsmrzx/p/11253432.html
Copyright © 2011-2022 走看看