Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
原理:
使用state数据的组件可以对其共享数据的状态进行改变,通过改变状态更新数据从而重新渲染页面
-
state: vuex的共享数据源,其为一个对象以属性的方式存储公共数据1.2
Getters当多个使用组件使用state共享数据需要进行过滤时,可以使用Getters添加对应的计算方法; 其效果类似Vue计算属性,
getters的结果像计算属性一样会被缓存起来,直到state中对应的数据发生改变。
// Getter 接受 state 作为其第一个参数
const store = createStore({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: (state) => {
return state.todos.filter(todo => todo.done)
}
}
})
我们可以通过this.$store.getters,以属性的形式获取getters的结果。在使用时可以通过插值表达式直接引入,也可以使用一个计算属性。
<h1>{{$store.getters.doneTodos}}</h1>
computed: {
doneTodos () {
return this.$store.getters.doneTodos
}
}
使用 mapGetters 辅助函数生成计算属性
同样的,我们可以使用 mapGetters 辅助函数帮助我们生成计算属性。
import { mapGetters } from 'vuex'
export default {
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
...mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
如果你想将一个 `getter` 属性另取一个名字,使用对象形式:
export default { methods:{ add(){ this.$store.dispatch('addnum',2) } } }
-
dispatch:派遣
组件可以过dispatch向action提交状态和携带的值。
-
actions:动作
在
Actions里设置Dispath对应状态的应对方法。多数情况actions为一个预备确定状态机制,当
dispatch携带的值不确定,需要进行异步操作才能获取时actions为其进行与后台请求的异步操作,在得到参数后使用Commit向Mutation进行提交最终的请求状态。 因为 mutation 必须同步执行所以我们在actions内部执行异步操作:
actions: {
// 回调的第一个参数为上下文state,可以直接结构出Commit
addnum({commit},value){
setTimeout(() => {
commit('ADDNUM',value)
}, 1000);
},
delnum({commit},value){
setTimeout(() => {
commit('DELNUM',value)
}, 1000);
}
}
-
Commit :提交
Commit为提交状态机制,当提交的状态无需进行异步操作时可直接通过Commit向Mutation提交状态- 直接触发:
this.$store.commit('DEL',this.shuzi)
当需要异步操作时,以Actions触发
addajax: function ({ commit }, data) {
setTimeout(() => {
state中的值 */
commit('ADD', data)
}, 500)
}
},
-
Mutation :改变
想要更改 state 中的数据,我们必须通过commit提交一个mutation,每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler),回调函数接受 state作为第一个参数,也可以传入额外的参数作为第二个参数。
const store = createStore({
state: {
count: 1
},
mutations: {
// 每个mutation的回调函数名一般大写,用以和actions里的回调函数名作区分
INCREMENT (state) {
// 变更状态
state.count++
}
}
})
// 组件内的方法。通过一个事件调用`commit`方法去调用 `mutation` 处理函数
methods:{
add(){
this.$store.commit('INCREMENT')
}
}
-
Modules:块化化
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module) 。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
// modeA.js
const state = ()=>({
modeAMsg:'模块A的msg'
})
const getters = {
getMsgOfA:(state)=> state.modeAMsg+'--getters'
}
const mutations = {
CHANGEMSGOFA(state,value){
state.modeAMsg = value
}
}
const actions = {
changemsgAwait({commit},value){
setTimeout(() => {
commit('CHANGEMSGOFA',value)
}, 3000);
}
}
export default {
// 如果希望你的模块具有更高的封装度和复用性,你可以通过添加 `namespaced: true` 的方式使其成为带命名空间的模块。
namespaced:true,
state,
getters,
mutations,
actions
}
// index.js
import Vue from 'vue'
import Vuex from 'vuex'
// 导入
import modeA from '@/store/modules/modeA'
Vue.use(Vuex)
export default new Vuex.Store({
// 注册
modules: {
modeA
}
})
使用modulesa
在组件中使用modeA
通过this.$store.state.modeA.modeAMsg可以访问modeA中的modeAMsg。
通过this.$store.getters['modeA/getMsgOfA']可以访问modeA中的getMsgOfA。
调用commit方法调用modeA中的mutation。
changeFn1(){
this.$store.commit('modeA/CHANGEMSGOFA',prompt('请输入改变后的值'))
},
复制代码
复制代码
调用dispatch方法调用modeA中的action。
changeFn2(){
this.$store.dispatch('modeA/changemsgAwait',prompt('请输入改变后的值'))
},
复制代码
复制代码
使用辅助函数
当使用 mapState、mapGetters、mapActions 和 mapMutations 这些函数来绑定带命名空间的模块时,写起来可能比较繁琐,可以将模块的空间名称字符串作为第一个参数传递给上述函数,这样所有绑定都会自动将该模块作为上下文。
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
export default {
computed:{
...mapState('modeA',['modeAMsg']),
// 使用都对象的写法重命名属性
...mapState(a:state=>state.modeA.modeAMsg)
...mapGetters('modeA',['getMsgOfA'])
},
methods:{
...mapMutations('modeA',['CHANGEMSGOFA']),
// 使用都对象的写法重命名属性
...MapMutations('modeA',{changemsg:'HANGEMSGOFA'})
...mapActions('modeA',['changemsgAwait'])
}
}
-
Mixins:混入
Vue为需要使用相同功能的组件提供的便捷方式。
1.局部混入,导出后在所需的应用以插件的方式使用。(导入加注册)
/* 把公共的内容放在mixinsA js文件中 */
export default {
data: function () {
return {
msg: 'vue初始化已完毕!'
}
},
created: function () {
console.log(this.msg)
},
methods: {
fn: function () {
alert(this.msg)
}
}
}
<template>
<div class="about">
<h1>This is an about page</h1>
<h1 @click="fn">{{msg}}</h1>
</div>
</template>
<script>
import mixinsA from '@/mixins/mixinsA.js'
export default {
name:"AboutView",
/* 以下内容每个vue页面都需要使用 */
mixins:[mixinsA]
}
</script>
-
全局混入
使用时格外小心!一旦使用全局混入,它将影响每一个之后创建的 Vue 实例
(包括第三方组件)。
//# main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
/*
请谨慎使用全局混入,因为它会影响每个单独创建的 Vue 实例 (包括第三方组件)。
大多数情况下,只应当应用于自定义选项。
推荐将其作为插件发布,以避免重复应用混入。
*/
/* 全局混入 */
Vue.mixin({
created:function(){
console.log('全局init....')
}
})
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
选项合并★
当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。
比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。
同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。
值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。