VueX
Vuex 状态管理器
一、Vuex 状态管理器
Vuex的原理
概念:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
应用场景:Vue多个组件之间需要共享数据或状态。
Vuex有几个核心属性:State、Getter、Mutation、Action、Module。
- State:存储状态数据
- Getter:从状态数据派生数据,相当于State的计算属性。
- Mutation:存储用于同步更改状态数据的方法,默认传入的参数为state。
- Action:存储用于异步更改状态数据,但不是直接更改,而是通过触发Mutation方法实现,默认参数为context。
- Module:Vuex模块化。
全局配置Vuex
在 src 目录下创建 store 文件夹,并在里面创建一个index.js文件,然后index.js中配置如下:
// 第一步:引入Vue、和Vuex(固定写法)
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
// 第二步:声明Vuex 的五个属性,其中state,mutations 是一定要定义的,其他的三个属性对象根据实际需要。
const state = { // 初始化状态值--一定要有该属性对象
...
}
const mutations = { // 自定义改变state初始值的方法--一定要有该属性对象
...
}
const getters = { // 状态计算属性--该属性对象不是必须
...
}
const actions = { // 异步操作状态--该属性对象不是必须的
...
}
const modules = { // 状态模块--该属性对象不是必须的
...
}
// 第三步:创建一个 store 实例,将声明的五个变量赋值赋值给 store 实例,如下:
const store = new Vuex.Store({
state,
mutations,
//下面三个非必须
getters,
actions,
modules
})
// 第四步:导出 store 实例,供外部访问
export default store
在项目的main.js中将Vuex注册到全局实例中
...
import store from './store'
...
new Vue({
el: '#app',
router,
store, //注入,组件中可以使用 this.$store 获取
components: { App },
})
配置流程
梳理一下 Vuex 的配置流程:
- 1.声明 state 对象,存放要初始状态的数据对象
- 2.声明 getters 对象,存放 派生state中数据的方法(store计算属性)
- 3.声明 mutations 对象,存放 设置 state中数据的方法(同步操作)
- 4.声明 actions 对象,存放 异步操作 mutations中的方法的方法(异步操作)
- 5.声明 modules 对象, 存放 外部模板 文件 (如果没有创建外部 js 文件,次步可去除)
- 6.创建 Vuex 实例,注入上面声明的对象,并用export default导出,然后再在main.js中将 Vuex 挂在到Vue实例中
再简单看一下基本使用的语法:
- 1.获取 某个状态的值: index.js 中的 obj 的值:this.$store.state.obj
- index.js 中的 obj 的值:this.$store.getters.obj
- page1.js 中的 arr 的值:this.$store.state[ "page1/arr" ]
- page1.js 中的 arr 的值:this.$store.getters[ "page1/arr" ]
- 2.设置 某个状态的值: index.js 中的 obj 的值:this.$store.commit( "obj" , val )
- index.js 中的 obj 的值:this.$store.dispatch( "obj" , val ))
- page1.js 中的 arr 的值:this.$store.commit( "page1/arr" , val ))
- page1.js 中的 arr 的值:this.$store.dispatch( "page1/arr" , val )
各模块在流程中的功能
- Vue Components:Vue组件。HTML页面上,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。
- dispatch:操作行为触发方法,是唯一能执行action的方法。
- actions:操作行为处理模块,由组件中的$store.dispatch('action 名称', data1)来触发。然后由commit()来触发mutation的调用 , 间接更新 state。负责处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。
- commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
- mutations:状态改变操作方法,由actions中的commit('mutation 名称')来触发。是Vuex修改state的唯一推荐方法。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。
- state:页面状态管理容器对象。集中存储Vue components中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。
- getters:state对象读取方法。图中没有单独列出该模块,应该被包含在了render中,Vue Components通过该方法读取全局state对象。
Vuex与localStorage
vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态,具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。
Vue.sync的用法
日常开发时,我们总会遇到需要父子组件双向绑定的问题,但是考虑到组件的可维护性,vue中是不允许子组件改变父组件传的props值的。那么同时,vue中也提供了一种解决方案.sync修饰符。在此之前,希望你已经知道了vue中是如何通过事件的方式实现子组件修改父组件的data的。
.sync修饰符
首先我们知道,父组件通过绑定属性的方式向子组件传值,而在子组件中可以通过$emit向父组件通信,通过这种间接的方式改变父组件的data,从而实现子组件改变props的值。比如向下边这这样:
子组件使用$emit向父组件发送事件:
this.$emit('update:title', newTitle)
父组件监听这个事件并更新一个本地的数据title
<text-document
:title="title"
@update:title="val => title = val"
>
为了方便这种写法,vue提供了.sync修饰符,说白了就是一种简写的方式,我们可以将其当作是一种语法糖,比如v-on: click可以简写为@click。而上边父组件的这种写法,换成sync的方式就像下边这样:
<text-document
:title.sync="title"
>
有没有发现很清晰,而子组件中我们的写法不变,其实这两种写法是等价的,只是一个语法糖而已,如果到这里你还不太明白。下边是个完整的demo,可以copy自己的项目中尝试一下。相信你会恍然大悟。
父组件
<template>
<div>
<child :name.sync="name"></child>
<button @click="al">点击</button>
<button @click="change">改变</button>
</div>
</template>
<script>
import child from './child'
export default {
name: 'list',
components: {
child
},
data () {
return {
listItems: ['buy food', 'play games', 'sleep'],
name: 'xiaoming'
}
},
methods: {
al() {
alert(this.name);
},
change() {
this.name = '123';
}
}
}
</script>
子组件:
<template>
<div>
<input :value="name" @input="abc" type="text">
</div>
</template>
<script>
export default {
props: {
name: {
type: String,
required: true
}
},
methods: {
abc(e) {
console.log(e.target.value);
this.$emit('update:name', e.target.value);
}
}
}
</script>
sync修饰符,与我们平常使用$emit实现父子组件通信没有区别,只不过是写法上方便一些。当然,利用引用类型的特性实现双向绑定我认为也并非完全不可取。
vuex的适用场景
在项目开发中,可能会有很多数据或者参数我们可能需要多次读取或者修改,像购物车等类似功能,这个时候我们的就可以用vuex来实现;vuex毕竟只是一个状态管理模式,状态管理模式是给我们提供方便的,但不是必需的,因为状态管理能做的事通过其他途径和办法也能实现。