VUEX
1、VueX是做什么的
官方解释:Vuex是一个专为Vue.js 应用程序开发的状态管理模式。
它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex也集成到vue 的官方调试工具devtools extension,提供了诸如零配置的 time-travel调试、状态快照导入导出等高级调试
功能。
1.1、状态管理到底是什么?
状态管理模式、集中式存储管理这些名词听起来就非常高大上,让人捉摸不透。
其实,你可以简单的将其看成把需要多个组件共享的变量全部存储在一个对象里面。
然后,将这个对象放在顶层的Vue实例中,让其他组件可以使用。
那么,多个组件是不是就可以共享这个对象中的所有变量属性了呢?
1.2、有什么状态时需要我们在多个组件间共享
多个状态,在多个界面间的共享问题。
比如用户的登录状态、用户名称、头像、地理位置信息等等。
比如商品的收藏、购物车中的物品等等。
这些状态信息,我们都可以放在统一的地方,对它进行保存和管理,而且它们还是响应式的
2、安装vuex
npm install vuex --save
3、使用Vuex
3.1、配置vuex
//创建一个store文件夹
//新建index。js
import Vue from 'vue'
import Vuex from 'vuex'
// 1\安装插件
Vue.use(Vuex)
// 2\创建对象
//项目中最好只能有一个store
const store =new Vuex.Store({
// 状态
state:{
//公用的状态/变量
conuter:0
},
//方法
//修改状态(默认参数state对象
mutations:{
increment(state){
state.counter++
},
decrement(state){
state.counter--
}
},
actions:{
},
getters:{
},
modules:{
}
})
// 3\导出对象
export default store
3.2、在main中引入
import Vue from 'vue'
import App from './App'
import router from './router'
import store from '../store/index'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})
3.3 、在组件中使用
<template>
<div>
<h2>--------组件内容-------</h2>
{{msg}}
<button @click="add">+</button>
<button @click="del">-</button>
<!-- 使用store中的state对象 -->
{{$store.state.counter}}
</div>
</template>
<script>
export default {
name: 'Learn',
data () {
return {
msg:'hello vuex'
}
},
methods: {
add(){
// 使用store中mutations方法修改state
this.$store.commit('increment')
},
del(){
this.$store.commit('decrement')
}
},
}
</script>
3.4、getters
// 类似组件的计算属性
getters:{
powerCounter(state){
return state.num * state.num
},
more17stu(state){
return state.stu.filter((s)=>{
return s.age > 17
})
// 简写
// return state.stu.filter(s => s.age > 17)
},
// 可将getter作为参数传入
// state和getters的顺序的固定的
more17stulength(state,getters){
return getters.more17stu.length
},
// getters需要自定义参数时可先返回一个参数
moreAgeStu(state){
return function (age) {
return state.stu.filter((s)=>{
return s.age >age
})
}
}
},
//使用
{{$store.getters.more17stu}}
{{$store.getters.more17stulength}}
{{$store.getters.moreAgeStu(20)}}
3.5、mutation
// store中state更新的唯一方式
// 第一个参数固定位state
mutations:{
increment(state){
state.counter++
},
decrement(state){
state.counter--
},
},
//使用
methods:{
del(){
this.$store.commit('decrement')
},
}
3.5.1、payload
// 第一个参数固定位state
// 第二个参数为接收参数
// incrementCount(state,count){
// state.counter+=count
// }
// 使用封装方法提交参数时,payload为一个对象,可传递多个值
incrementCount(state,payload){
console.log(payload)
state.counter+=payload.count
},
//使用
methods:{
addCount(count){
// this.$store.commit('incrementCount',额外传递的参数)
// 此参数被称为payload:载荷/负载
// 1、普通提交风格
// this.$store.commit('incrementCount',count)
// 2、特殊的提交封装
// 此时可传递多个值
this.$store.commit({
type:'incrementCount',
count,
age:17
})
}
}
3.5.2、响应式修改数据
// 只有最开始加入state中的数据才会加入响应式系统中,后续新增的不会添加至响应式系统
// 若需要加入响应式的数据,可使用Vue.set()
// 响应式删除数据,可使用Vue.delete
mutation:{
changeInfo(state){
// 添加响应式数据
Vue.set(state.info,'address','home')
// 响应式删除数据
Vue.delete(state.info,'age')
}
}
3.5.3、自定义mutation常量
Vue官方推荐写法,非强制要求的格式
组件和vuex中均需引入并使用常量
//新建mutation-types.js
//导出自定义常量
export const INCREMENT ='increment'
//引入并使用常量
//组件中
//导入
import {
INCREMENT
} from '../../store/mutations-types'
//使用
methods:{
add(){
// 使用定义的mutation常量
this.$store.commit(INCREMENT)
},
}
//VueX中
import {
INCREMENT
} from '../store/mutations-types'
mutations:{
[INCREMENT](state){
state.counter++
},
}
3.5.4 、mutations中不推荐使用异步操作(ajax,定时器等
因为进行异步操作devtools无法进行监听
如果需要异步操作,则使用action执行mutation中的事件
(因为禁止绕过mutation修改state
3.6、actions
// context为上下文,此处为$store
// payload 为传递的参数
aupidateInfo(context,payload){
setTimeout(()=>{
// context.commit('mutation中的事件')
context.commit('changeInfo')
console.log(payload)
},1000)
}
//使用
this.$store.dispatch('aupidateInfo','我是payload')
3.6.1、执行完异步操作需要放回参数/执行回调
使用promise对异步操作进行封装
//若异步操作完成后需执行回调/返回参数
// 可使用promise进行封装
aupidateInfo(context,payload){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
// context.commit('mutation中的事件')
context.commit('changeInfo')
console.log(payload)
resolve('异步执行成功')
},1000)
})
}
//使用
// 使用promise封装异步操作
this.$store.dispatch('aupidateInfo','我是payload').then((data)=>{
console.log(data)
})
3.7、modules
//Vue使用单—状态树,那么也意味着很多状态都会交给vuex来管理.
//当应用变得非常复杂时,store对象就有可能变得相当臃肿.
//为了解决这个问题, Vuex允许我们将store分割成模块(Module),而每个模块拥有自己的state、mutations.actions、getters等
const moduleA={
state:{
name:'张三'
},
mutations:{
updataname(state,payload){
state.name=payload
}
},
actions:{
// 此处的context只能是当前的模块
aUpdateName(context){
setTimeout(()=>{
context.commit('updataname','王五')
},1000)
}
},
getters:{
fullname(state){
return state.name+'1111'
},
fullname2(state,getters){
return getters.fullname+'22222'
},
// modules中可以有第三个参数rootState
fullname3(state,getters,rootState){
return getters.fullname2+rootState.counter
}
}
}
const moduleB={
state:{},
mutations:{},
actions:{},
getters:{}
}
const store =new Vuex.Store({
modules:{
a:moduleA,
b:moduleB
}
})
//使用
<h2>-------使用modules中的内容-------</h2>
{{$store.state.a.name}}
<button @click="changname">修改名字</button>
{{$store.getters.fullname}}
{{$store.getters.fullname2}}
{{$store.getters.fullname3}}
<button @click="asyncname">action修改名字</button>
methods:{
changname(){
this.$store.commit('updataname','李四')
},
asyncname(){
this.$store.dispatch('aUpdateName')
}
}
3.8、store文件夹推荐目录结构
//将mutations,actions,getters单独抽离成一个js文件,并使用import导入
//state抽离至new Vuex外
//modules抽离至单独的文件夹中
import Vue from 'vue'
import Vuex from 'vuex'
import moduleA from './modules/moduleA'
import mutations from './mutations'
import getters from './getters'
import actions from './actions'
// 1\安装插件
Vue.use(Vuex)
// store抽离
const state = {
counter:0,
num:999,
stu:[
{id:110,name:'aaa',age:14},
{id:110,name:'aaa',age:24},
{id:110,name:'aaa',age:19},
{id:110,name:'aaa',age:15},
{id:110,name:'aaa',age:17},
{id:110,name:'aaa',age:22},
],
info:{
name:'me',
age:15,
height:156
}
}
const store =new Vuex.Store({
state,
mutations,
actions,
getters,
modules:{
a:moduleA,
}
})
// 3\导出对象
export default store
4、Devtools
vuex监听mutations修改的插件
5、单一状态数
英文名称是Single Source of Truth,也可以翻译成单一数据源。