1. Vuex简介
Vuex是为vue.js应用程序开发的状态管理模式,解决的问题:
◊ 组件之间的传参,多层嵌套组件之间的传参以及各组件之间耦合度过高问题
◊ 不同状态中的行为需要多份复制的问题
Vuex采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
核心思想:抽取组件的共享状态,以一个全局单例的模式进行管理。
核心:store(仓库)
核心组成:
◊ state:存放项目中需要多组件共享的状态变量
◊ getters:读取器,从state中派生出状态,如:将state中的某个状态进行过滤然后获取新的状态。
◊ mutations:修改器,存放更改state里状态的方法。
◊ actions:动作,mutation的加强版,可以通过commit mutations中的方法来改变状态,最重要的是可以进行异步操作。
◊ modules:模块化,将状态和管理规则模块化封装。
Vuex文档:https://vuex.vuejs.org/zh/
2. Vuex基本使用
2.1 State
npm安装:
npm install vuex -S
基础示例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>libing.vue</title> <script src="node_modules/vue/dist/vue.min.js"></script> <script src="node_modules/vuex/dist/vuex.min.js"></script> </head> <body> <div id="app"> Copyright © {{ author }} - 2018 All rights reserved </div> <script> Vue.use(Vuex); const store = new Vuex.Store({ // 定义状态 state: { //key: value author: 'Libing' } }); new Vue({ el: "#app", store: store, computed: { author: function () { return this.$store.state.author } } }); </script> </body> </html>
vue-cli示例:
/store/index.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ // 定义状态 state: { //key: value author: 'libing' } })
HelloWorld.vue
<template> <div>Copyright © {{ author }} - 2018 All rights reserved</div> </template> <script> export default { name: "HelloWorld", computed: { author: function() { return this.$store.state.author; } } }; </script>
<template> <div id="app"> <HelloWorld/> </div> </template> <script> import HelloWorld from "./components/HelloWorld"; export default { name: "App", components: { HelloWorld } }; </script>
main.js
import Vue from 'vue' import App from './App' import store from './store/index' Vue.config.productionTip = false new Vue({ el: '#app', store, components: { App }, template: '<App/>' })
mapState:当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,可以使用 mapState 辅助函数帮助生成计算属性。
store/index.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { count: 1, todos: [{ id: 1, text: 'ToDo', status: false }, { id: 2, text: 'Doing', status: false }, { id: 3, text: 'Done', status: true } ] } })
Home.vue
<template> <div class="home"> <ul> <li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li> </ul> </div> </template> <script> import { mapState } from "vuex" export default { computed: mapState({ count: state => state.count, todos: state => state.todos, dones(state) { return state.todos.filter(todo => todo.status); } }) }; </script>
2.2 Getter
Vuex 允许在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
Getter 接受 state 作为其第一个参数:
store/index.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { count: 1, todos: [{ id: 1, text: 'ToDo', status: false }, { id: 2, text: 'Doing', status: false }, { id: 3, text: 'Done', status: true } ] }, getters: { dones: state => { return state.todos.filter(todo => todo.status); } } })
Getter 会暴露为 store.getters
对象,以属性的形式访问这些值:
Home.vue
<template> <div class="home"> <ul> <li v-for="todo in dones" :key="todo.id">{{ todo.text }}</li> </ul> </div> </template> <script> export default { computed: { dones() { return this.$store.getters.dones; } } }; </script>
通过方法访问,让 getter 返回一个函数,来实现给 getter 传参。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { count: 1, todos: [{ id: 1, text: 'ToDo', status: false }, { id: 2, text: 'Doing', status: false }, { id: 3, text: 'Done', status: true } ] }, getters: { dones: state => { return state.todos.filter(todo => todo.status); }, getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id); } } })
Getter 也可以接受其他 getter 作为第二个参数:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { count: 1, todos: [{ id: 1, text: 'ToDo', status: false }, { id: 2, text: 'Doing', status: false }, { id: 3, text: 'Done', status: true } ] }, getters: { dones: state => { return state.todos.filter(todo => todo.status); }, donesCount(state, getters) { return getters.dones.length; } } })
2.3 Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
不能直接调用一个 mutation handler,要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit()。
store/index.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { count: 0 }, mutations: { increment(state) { state.count++; } } })
Home.vue
<template> <div class="home"> {{ count }} <input type="button" value="添加" @click='handleIncrement'> </div> </template> <script> export default { data() { return { count: this.$store.state.count }; }, methods: { handleIncrement() { this.$store.commit("increment"); console.log(this.$store.state.count) } } }; </script>
2.4 Action
Action 类似于 mutation,不同在于:
◊ Action 提交的是 mutation,而不是直接变更状态。
◊ Action 可以包含任意异步操作。
store/index.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { count: 0 }, mutations:{ increment(state) { state.count++; } }, actions:{ plus(context){ context.commit('increment') } } })
Home.vue
<template> <div class="home"> {{ count }} <input type="button" value="添加" @click='add'> </div> </template> <script> export default { computed: { count() { return this.$store.state.count; } }, methods: { add() { this.$store.dispatch('plus'); } } }; </script>