前言
此篇为本人自学时做的笔记,不完全算教学篇,如有错误或解释不清楚的地方,或者有更好的建议,请指出,我会及时更正
一、vuex的介绍
1.概述
vuex是一个vue中的一个插件,可以帮我们管理vue通用(多组件共享)的数据
2.应用场景
某个或某些数据被多个组件共享
3.优势
3.1数据集中化管理
在使用vuex之前,在创建的组件越来越多的情况下,组件之间的数据操作会越来越麻烦,学习vuex之后,可以使数据集中化管理,即把数据放在一个特有的地方,可看作是一个仓库,所有组件都可以直接通过仓库操作数据
3.2响应式变化
任意一个组件对仓库的数据进行修改时,随着仓库中数据的变化,所有用到该仓库数据的组件都会随之响应式更新(一个变化全都变)
3.3语法简洁
vuex中提供了一些辅助函数,帮助我们更加简洁快速的操作仓库中的数据
二、 vuex的基本使用
如何创建一个存放数据的仓库
1.安装vuex
创建好VueCli项目后,在该项目中打开终端
输入yarn add vuex@3 或npm install vuex@3
注:如果使用npm安装出现报错,需在后面添加--legacy-peer-deps
2.新建vuex模块文件
在src目录下创建一个store(仓库)目录,在该目录下创建index.js文件
所有与vuex相关的核心代码都写在新建的index.js文件中
3.创建仓库
4.在main.js中导入挂载
三、vuex的进阶使用
在3.3中提到了vuex提供了许多简洁的语法及函数,我会详细介绍它们的用法
1.state状态(数据)
学习state可以掌握如何给仓库提供数据,如何使用仓库中的数据
1.1在仓库中通过state提供、存储数据
1.2使用数据
第一种:通过store直接访问
第二种:通过mapState辅助函数(语法简洁)
mapState是 Vuex 提供的一个辅助函数,用于将 Vuex 的状态映射到 Vue 组件的计算属性中
使用辅助函数前,需要用{{ $store.state.msg }}来获取值,通过mapState函数的使用,我们可以直接用{{msg}}显示数据,简洁了语法
问:为什么要用展开运算符?
使用展开运算符之前
computed:mapState(['msg','count'])
这样的写法是正确的,但是缺少了可拓展性,即不能添加额外的其他计算属性,所以更改成
computed: { ...mapState(['msg', 'count']), outerComputed(){ //其他计算属性 } }
问:为什么更改之后要用展开运算符?有什么区别?
不使用展开运算符时:
computed: { mapState(['msg', 'count']) }
这段代码等效于
computed: { mapState: mapState(['msg', 'count']) }
使用展开运算符后:
computed: { ...mapState(['msg', 'count']) }
等效于以下代码
computed: { msg() { return this.$store.state.msg; }, count() { return this.$store.state.count; } }
总结:
使用展开运算符:
computed: { ...mapState(['msg', 'count']) }
使msg
和count
成为computed
的直接属性。不使用展开运算符:
computed: { mapState(['msg', 'count']) }
会导致computed
中包含一个mapState
属性,而不是将msg
和count
展开为计算属性。
2.mutations(修改数据)
由于vuex同样遵循单项数据流,即组件中不能直接修改仓库数据
错误写法:
this.$store.state.count++// 直接在组件中修改仓库中的数据
注:该错误写法不会报错,对于初学者来说我们希望将错误代码实现报错,可开启严格模式
const store = new Vuex.Store({ strict: true,//开启严格模式,项目上线时需关闭,减少性能消耗 state:{ count:180 } })
正确写法:
2.1通过mutations定义方法修改数据
const store = new vuex.Store({
state: {
count: 0,
msg: 'hello vuex'
},
// 1.定义mutations
mutations: {
add (state) {
state.count++//增加数据
},
sub (state) {
state.count--//减少数据
}
}
})
2.2给要修改的数据添加方法,例如给按钮添加点击事件绑定方法
<button @click="addDemo">值 + 1</button>
2.3在下方注册方法,提交调用mutation
methods: {
addDemo() {
this.$store.commit('add')
}
注:1.提交的名字要与1.中定义的方法名相同
2.mutations定义方法可传参,但第一个参数必须为state
3.mutations参数只能多传一个,如果存在需要传入多个参数的情况,需打包成对象或数组的形式
this.$store.commit('add',obj)
2.4mapMutations辅助函数(简洁语法)
mapMutations 和 mapState很像,它是把位于mutations中的方法提取了出来,映射到组件methods中
例如:在mutations中定义的一个add和一个sub方法
const store = new vuex.Store({
state: {
count: 0,
msg: 'hello vuex'
},
// 1.定义mutations
mutations: {
add (state) {
state.count++
},
sub (state) {
state.count--
}
}
})
在组件中导入mapMutations包
import { mapMutations } from 'vuex'
在下方methods中使用mapMutations包
//用辅助函数前
methods: {
addDemo () {
this.$store.commit('add')
}
subDemo () {
this.$store.commit('sub')
}
}
methods: {
...mapMutations(['add','sub'])//用辅助函数后,语法更简洁
}
这样就可以直接在组件中用add(),sub()调用方法
<button @click="add">值 + 1</button>
注:如果同时使用mapMutations 和 mapState,在导包时可能会遇到以下错误
解决方法:只需修改成下列代码即可
import { mapState, mapMutations } from 'vuex'
3. actions(异步操作)
actions用于处理异步操作,例如两秒后将数据改为xxx,请求数据等
注:actions不饿能直接操作state,操作state还是需要commit mutation
3.1在store仓库中通过mutations注册方法用来修改state
mutations: {
add (state,num) {
state.count = state.count + num
}
},
3.2在store仓库中注册actions
actions: {
setNum (context, num) {
// 一秒后,调用add方法,使num+1
setTimeout(() => {
context.commit('add', num)//add为mutations中定义的方法
}, 1000)
}
}
3.3在页面中用dispatch语法调用
this.$store.dispatch('setNum',180)
3.4mapActions(简洁语法)
与上面两个同理,actions也有自己的辅助函数,语法与上面两个相同
// 1.导入mapActions包
import { mapActions } from 'vuex'
// 2.使用mapActions包
methods: {
...mapActions(['setNum'])
}
// 3.应用
<button @click="setNum(180)">1s后值 + 180</button>
4.getters(类似计算属性)
除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters
例如:在state中新定义一个list数组,要求显示所有大于5的数据
state:{
list:[1,2,3,4,5,6,7,8,9,10]
}
操作步骤:
// 1.定义getters filterList(state) { return state.list.filter(item => item > 5) // 用filter 过滤出大于五的数据 }
注:1.getters函数的第一个参数必须是state
2.getters函数必须要有返回值
// 2.通过store访问getters {{ $store.list.filterList}}
同样,getters也有自己的辅助函数mapGetters,用法与前三个类似
// 1.导入mapGetters包 import { mapGetters } from 'vuex'
// 2.使用mapGetters包 computed: { ...mapGetters(['filterList']) }
// 3.应用 <div>{{ fliterList }}</div>
注:由于getters与计算属性类似,所以放在computed中而不是methods中,
应用时直接用{{ fliterList }}而不是像方法 fliterList()那样调用
5.module(进阶语法)
随着仓库中state数据越来越多,项目的可维护性变差,此时需要module语法使state模块化,即把数据分给多个不同的模块js组件,再通过moudule挂载回state上,实现数据的拆分,便于更好的维护
5.1新建一个module文件夹,用来装模块文件,这里举例建了两个模块文件
5.2在新建的模块文件中编写对应模块内容的数据即可
5.3在index.js中导入挂载
// 1.导入 import uesr from './module/uesr' import setting from './module/setting'
//挂载 modules: { uesr, setting }
// 3.应用 // 根据vue调试工具查看路径 <h2>{{ $store.state.setting.modulestate }}</h2>
也可通过mapState辅助函数来简洁语法
computed: {
...mapState(['setting'])
}
注:由上图我们可以得知setting返回的是一个对象(Object)
所以应用时需要用
<h2>{{ Object.moudelestate }}</h2>
来获取数据
那么我们直接通过setting子模块来获取值而不是根模块,是不是就能简洁一步操作呢?
只需两步
export default {
namespaced: true, // 1.在子模块中开启命名空间
state,
mutations,
actions,
getters
}
// 2.通过子模块组件直接获取
computed: {
// ...mapState('模块名', ['xxx'])
// 例如
...mapState('setting', ['modulestate'])
}
这样就可以直接通过{{ modulestate}}来获取数据