vuex插件的学习
1.目的:$bus不善于处理组件过多时的数据通信,vuex的引入目的在于更好的实现多组件之间的数据共享
2.运作原理:vuex类似于全局变量,将要共享的数据及其操作方法独立出去,实现共享数据与组件解耦
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JWdMmiO5-1648954916682)(…/…/%E8%B5%84%E6%96%99%EF%BC%88%E5%90%AB%E8%AF%BE%E4%BB%B6%EF%BC%89/02_%E5%8E%9F%E7%90%86%E5%9B%BE/vuex.png)]
3.使用步骤:
- 下载:npm install vuex -s
- 导入插件:import Vuex from ‘vuex’
- 注册插件:Vue.use(Vuex)
- 挂载store:
- 创建store对象
4.vuex中的角色:
5.基础演示
<template>
<div>
<h1>当前求和为:{{ sum }}</h1>
<h1>当前求和十倍为:{{ bigSum }}</h1>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="increment(n)">+</button>
<button @click="decrement(n)">-</button>
<button @click="incrementOdd(n)">当前求和为奇数再加</button>
<button @click="incrementWait(n)">等一等再加</button>
</div>
</template>
data() {
return {
n: 1, // 用户选择的数字
}
},
methods: {
// 调用加的方法
increment() {
this.$store.commit('ADD', this.n)
},
// 调用减的方法
decrement() {
this.$store.commit('SUB', this.n)
},
// 奇数再加
incrementOdd() {
this.$store.dispatch('oddAdd', this.n)
},
// 延迟加
incrementWait() {
this.$store.dispatch('waitAdd', this.n)
},
},
computed: {
sum() {
return this.$store.state.sum
},
bigSum() {
return this.$store.getters.bigSum
},
store.js:
// 状态
const state = {
sum: 0,
}
// 响应者
const actions = {
// context是上下文,上下文即是vue封装的相关信息对象
// value是附带的参数
oddAdd(context, value) {
console.log('我处理了一些事,其它交给oddAddExpand处理')
// 业务逻辑比较复杂可以开启职责链模式,这也是为什么这里的参数是 context而不直接是commit
context.dispatch('oddAddExpand', value)
},
oddAddExpand(context, value) {
context.state.sum % 2 !== 0 && context.commit('ODDADD', value)
},
waitAdd(context, value) {
setTimeout(() => {
context.commit('WAITADD', value)
}, 2000)
},
}
// 操作者
const mutations = {
// state是状态,value是commit附带的参数
ADD(state, value) {
state.sum += value
},
SUB(state, value) {
state.sum -= value
},
ODDADD(state, value) {
state.sum += value
},
WAITADD(state, value) {
state.sum += value
},
}
// 数据装饰者,是在业务处理后对数据做最后处理的对象
const getters = {
bigSum(state) {
return state.sum * 10
},
}
6.开发者工具使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FcN117Wb-1648954916683)(…/…/…/…/AppData/Roaming/Typora/typora-user-images/image-20211211201536591.png)]
7.进阶演示
8.map的使用
-
mapState
写法: …mapState([‘personList’]) 或…mapState({personList:‘personList’})
等价于: personList=function(){return this.$store.state.personList}
-
mapActions同理
-
mapMutations同理
-
mapGetters同理
9.模块化
-
加减模块
// 加减业务模块 export default { namespaced: true, state: { sum: 0 }, getters: { // 数据装饰者,是在业务判断后对数据做最后处理的角色 bigSum(state) { return state.sum * 10 }, }, actions: { // context是上下文,上下文即是vue封装的相关信息对象 // value是附带的参数 oddAdd(context, value) { console.log('我处理了一些事,其它交给oddAddExpand处理') // 业务逻辑比较复杂可以开启职责链模式,这也是为什么这里的参数是context而不直接是commit context.dispatch('oddAddExpand', value) }, oddAddExpand(context, value) { context.state.sum % 2 !== 0 && context.commit('ODDADD', value) }, waitAdd(context, value) { setTimeout(() => { context.commit('WAITADD', value) }, 2000) }, }, mutations: { // context是上下文,是vue提供的可能需要的对象 ADD(state, value) { state.sum += value }, SUB(state, value) { state.sum -= value }, ODDADD(state, value) { state.sum += value }, WAITADD(state, value) { state.sum += value }, }, }
-
人员管理模块
// 人员管理业务模块 export default { namespaced: true, state: { personList: [ { id: 1, name: 'wz' }, { id: 2, name: 'lh' }, { id: 3, name: 'xm' }, ], }, getters: { enhancePerson(state) { const persons = [ { id: 1, name: 'wzxxx' }, { id: 2, name: 'lhxxx' }, { id: 3, name: 'xmxxx' }, ] return persons }, }, actions: { addWang(context, value) { if (value.name.indexOf('王') === 0) { context.commit('ADD_PERSON', value) } else { alert('必须兴姓王') } }, }, mutations: { ADD_PERSON(state, value) { state.personList.push(value) }, }, }
-
store导入各模块
// 导入vue原型 import Vue from 'vue' // 导入Vuex原型 import Vuex from 'vuex' // 导入加减模块 import countOptions from './count' // 导入人员管理模块 import personOptions from './person' // 使用插件 Vue.use(Vuex) // 创建并导出vuex的管理者store export default new Vuex.Store({ // 模块化 modules: { countModule: countOptions, personModule: personOptions }, })
-
使用演示
map方式获取数据方法
mapState的使用
computed: { //等价于 personList=function(){return this.$store.state['personModule/personList']} ...mapState('personModule', ['personList']), },
mapGetters的使用
```javascript ...mapGetters('countModule', ['bigSum']), ```
mapMutations的使用
methohs:{ // 等价于 increment(){this.&store.commit('countModule/ADD')} ...mapMutations('countModule', { increment: 'ADD', decrement: 'SUB' }), }
mapActions的使用
// 奇数再加 ...mapActions('countModule', { incrementOdd: 'oddAdd', incrementWait: 'waitAdd' }),
手动方式获取数据方法
执行mutations
this.$store.commit('personModule/ADD_PERSON', personObj)
执行actions
this.$store.dispatch('personMoudule/addWang', personObj)
执行getters
enhancdPerson() { return this.$store.getters['personModule/enhancePerson'] },
执行state
sum() { return this.$store.state['countModule/sum']},
8.异步请求
界面
```html <template> <div> <button @click="findTalk({ pageNum: 1, pageSize: 6 })">获取说说</button> <div v-for="talk in talkList" :key="talk.id">{{ talk.content }}</div> </div> </template> <script> import { mapState, mapActions } from 'vuex' export default { computed: { ...mapState('talkModule', ['talkList']), }, methods: { ...mapActions('talkModule', ['findTalk']), }, } </script> ```
store中的talk模块action发起异步请求
配置vue-cli代理服务器解决同源问题
```javascript module.exports = { // 配值代理服务器 devServer: { proxy: { '/talk': { target: 'http://www.xxx.com', }, }, }, } ```
actions中发起异步请求, 成功时回调mutaptions中的方法,填入数据
// 导入axiosimport axios from 'axios'export default { namespaced: true, state: { talkList: [], }, actions: { // 获取说说请求 findTalk(context, value) { axios .get('talk/findTalkByPage', { params: value, }) .then( (resonse) => { // 解构赋值 const { data } = resonse const talks = data.talkList // 调用mutations处理数据 context.commit('FINDTALK', talks) }, (error) => { console.log(error) } ) }, }, mutations: { FINDTALK(state, talks) { // 清空原来的 state.talkList = [] // 填入数据 talks.forEach((talk) => { state.talkList.push(talk) }) }, },}
store导入talk模块并且注册
```javascript // 导入vue原型 import Vue from 'vue' // 导入Vuex原型 import Vuex from 'vuex' // 导入加减模块 import countOptions from './count' // 导入人员管理模块 import personOptions from './person' // 导入说说管理模块 import talkOptions from './talk' // 使用插件 Vue.use(Vuex) // 创建并导出vuex的管理者store export default new Vuex.Store({ // 模块化 modules: { countModule: countOptions, personModule: personOptions, talkModule: talkOptions }, }) ```
7.常见问题
①创建store之间一定要先使用vuex,因为import会提升
②要注意actions中的参数是context和value而mutations中的参数是state和value
③模块化的时候一定要加上命名空间namespaced:true,并且创建store时加上modules:{}
8.重点
context: actions的参数有一个是context,这个参数是上下文对象,所谓上下问对象即是vue为方便操作而封装的相关信息对象,与事件触发时event对象有相似的地方
9.其中用到的设计模式的思考
①职责链模式
在actions可以链式调用方法进行业务处理
oddAdd(context, value) { console.log('我处理了一些事,其它交给oddAddExpand处理') // 业务逻辑比较复杂可以开启职责链模式,这也是为什么这里的参数是 context而不直接是commit context.dispatch('oddAddExpand', value) }, oddAddExpand(context, value) { context.state.sum % 2 !== 0 && context.commit('ODDADD', value) },
②装饰器模式
// 数据装饰者,是在业务处理后对数据做最后处理的对象const getters = { bigSum(state) { return state.sum * 10 },}
10.总结**
Vuex是组件共享数据的一种解决方案其通过store来管理共享数据,其中
- state是保存共享数据的角色,里面保存了组件之间要共享的数据
- actions是进行业务逻辑判断的角色,主要进行逻辑判断选择调用哪个方法
- mutations数据操作角色,里面封装了共享数据操作方法
- getter数据装饰者,在业务逻辑处理完成后对数据进行最后操作的的角色
我们将store的挂载在Vue原型后,就可以使用this.$store来操作共享数据了,vuex会在状态变更时重新渲染页面
同时我们还可以进行模块化,仅仅需要配置再store中一个modules并导入对应模块就可以
- 对于map总结几点
- 对于手动操作几点总结