• 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学习笔记

    版权声明:本博客属于个人维护博客,未经博主允许不得转载其中文章。
  • 相关阅读:
    sublime开启vim模式
    git命令行界面
    搬进Github
    【POJ 2886】Who Gets the Most Candies?
    【UVA 1451】Average
    【CodeForces 625A】Guest From the Past
    【ZOJ 3480】Duck Typing
    【POJ 3320】Jessica's Reading Problemc(尺取法)
    【HDU 1445】Ride to School
    【HDU 5578】Friendship of Frog
  • 原文地址:https://www.cnblogs.com/wsmrzx/p/11253432.html
Copyright © 2020-2023  润新知