uniapp使用vuex和模块化后访问命名空间中的state、actions、mutations、getters
uniapp使用vuex和模块化后访问命名空间中的state、actions、mutations、gettersVuex的作用统一管理项目的公用数据,任所有组件都可以随时获取这些数据。在开发中我们通常会使用vuex结合**uni.getStorageSync**来储存用户登入后的状态、用户信息(头像、昵称、手机号)等,来实现缓存效果,避免每次打开app都需跳转到Login页面。使用方法在uni-a
uniapp使用vuex和模块化后访问命名空间中的state、actions、mutations、getters
Vuex的作用
统一管理项目的公用数据,任所有组件都可以随时获取这些数据。
在开发中我们通常会使用vuex结合**uni.getStorageSync**来储存用户登入后的状态、用户信息(头像、昵称、手机号)等,来实现缓存效果,避免每次打开app都需跳转到Login页面。
使用方法
在uni-app中内置了vuex,我们只需要在main.js
中引用就行了:
一、首先在根目录下创建store目录在里面创建index.js
并创建Store对象
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
modules: modules,
state: {
count:12,
hasLogin: false,
token: '',
},
getters: {},
mutations: {
setLogin(state, flag){
state.hasLogin = flag;
},
setToken(state, token){
state.token = token;
},
},
actions: {},
});
export default store;
二、将 store 对象挂载到 vue 实例main.js
中,为了方便调用,我们还可以把vuex挂载到vue原型上:
import App from './App'
// 引入vuex并挂载到原型
import store from './store/index.js'
Vue.prototype.$store = store
// #ifndef VUE3
import Vue from 'vue'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
// #endif
state 数据源
state 提供唯一的公共数据源,所有共享的数据都要统一放到
Store
的state
中进行存储。
使用方式
- 插值表达式获取
<view>{{$store.state.count}}</view>
- 在methods中直接使用state
this.$store.state.count
- 如果开启了模块化:
this.$store.state.模块名.模块属性
,使用插值表达式时可以省略this。 - 使用计算属性获取
- 未开启模块化:
...mapState(['模块名'])
- 开启模块化后使用方式:
...mapState(['模块名'],['属性名'])
- 未开启模块化:
示例:
直接使用
直接在组件中的computed
和methods
中使用 :
<template>
<view class="main">
<view> count的最新值为 {{count}}</view>
<view @click="getCode" class="send-message">获取验证码</view>
</view>
</template>
<script>
export default {
data () {
return {}
},
computed: {
school(){ return this.$store.state.count }
},
methods:{
getCode(){
phone = this.$store.state.phone
uni.navigateTo({ url: `./messige?phone=${phone}`})
}
}
}
</script>
mapState 映射为计算属性
通过 mapState 函数,将当前组件需要的全局数据,映射为 computed
计算属性:
// 1. 在想使用数据的组件中 从 vuex 中按需导入mapState函数
import { mapState } from 'vuex'
computed: {
/* 2. 将全局数据,映射为当前组件的计算属性 */
/* 借助mapState生成计算属性:count、school(数组写法)*/
...mapState(['sum','school','subject']),
/* 借助mapState生成计算属性:sum、school、subject(对象写法))*/
...mapState({sum:'sum',school:'school',subject:'subject'}),
}
mutations 用于变更数据
mutation
用于变更 store 中的数据,注意,vuex中的数据只能通过 mutation 更改,不可以在组件中直接更改,虽然这样操作起来稍微繁琐,但可以集中监控所有数据的变化。
使用方法:
仅用于同步方法更改数据:$store.commit('mutations中的方法名',数据)
示例
直接使用
在vuex中编写mutations
// 定义Mutation
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state) {
// 变更状态(更改数据)
state.count++
},
addN(state, step) {
// 变更状态(数据)
state.count += step
}
}
})
在组件中触发mutation
//
methods: {
handle1() {
this.$store.commit('add')
},
handle2() {
// 触发 mutations 时携带参数
this.$store.commit('addN', 3)
}
}
mapMutations 映射为方法
在vuex中编写mutations
// store
mutations: {
add(state) {
// 变更状态
state.count++
},
sub(state) {
state.count--
},
addN(state, step) {
// 变更状态
state.count += step
},
subN(state, step) {
state.count -= step
}
}
在组件中触发mutation
// 组件中使用
import { mapMutations } from 'vuex'
// 1. 从vuex中按需导入 mapMutations函数
import { mapMutations } from 'vuex'
// 2. 将指定的 mutations 函数,映射为当前组件的 methods 函数
methods:{
//使用 mapActions生成:sub、subN(对象形式)
...mapActions({incrementsub:'sub',incrementSubN:'subN'})
//使用 mapActions生成:sub、subN(数组形式)
...mapMutations(['sub','subN']),
// 调用
decrement(){
this.sub()
},
decrementN(){
this.subN(5)
}
}
Actions 用于处理异步操作
如果通过异步(网络请求) 操作变更数据,必须通过 action,而不能使用mutation,但是在 action中还是要通过触发mutation的方式间接变更数据。
- 在 actions 使用
commit('mutations中的方法名',数据)
触发 mutation。 - 在组件中触发 actions :
this.dispatch('action中的方法名',传递的数据)
备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch
,直接编写commit
。
使用方法:
直接使用:
在vuex中编写action
const store = new Vuex.store({
mutations: {
// 只有 mutations中的函数才有权利修改 state,不能在mutations里执行异步操作。
add(state) {
state.count++
}
},
actions: {
// 在 actions 中不能直接修改 state中的数据,要通过 mutations修改。
addAsync(context) {
setTimeout(() => {
context.commit('add')
}, 1000);
}
},
})
在组件中触发action
methods:{
handle(){
this.$store.dispatch('addAsync')
}
}
mapActions 映射为方法
// 1. 从Vuex中按需导入 mapActions 函数。
import {mapActions} from 'vuex'
// 2. 将指定的 actions 函数,映射为当前组件 methods 的方法。
methods:{
// 使用mapActions生成:subAsync (对象形式)
...mapActions({incrementSubAsync:'subAsync'})
// 使用mapActions生成:subAsync(数组形式)
...mapActions(['subAsync'])
// 调用:
decrementAsync(){
this.subAsync()
}
}
getter
Getter 用于对 Store中的数据进行加工处理形成新的数据。筛选或者排序显示。
- Getter 不会修改 Store 中的原数据,它只起到一个包装器的作用,将Store中的数据加工后输出出来。
- Store 中数据发生变化, Getter 的数据也会跟着变化。
使用方法
直接使用:
定义getters
//定义 Getter
const store = new Vuex.Store({
state:{
isLogin: false,
userInfo: uni.getStorageSync("userBaseInfo") || {}
},
getters: {
isLogin: state => state.isLogin,
userInfo: state => state.userInfo,
},
})
在组件中调用getters
this.$store.getters.名称
mapGetters 映射为计算属性
import { mapGetters } from 'vuex'
computed:{
...mapGetters(['showNum'])
}
简写 !!! 直接在标签上调用方法
其实,通过mapState,mapMutations,mapActions,mapGetters
映射过来的计算属性,或者方法都可以直接调用,不用在 commit
或者 dispatch
。
正常写法:
<button @click="decrementAsync"> -1Async</button>
import {mapActions} from 'vuex'
methods: {
...mapActions(['subAsync']),
decrementAsync(){
this.subAsync()
}
},
其实可以简写成:
<button @click="subAsync"> -1Async</button>
import {mapActions} from 'vuex'
//...省略一些代码
methods: {
...mapActions(['subAsync']),
},
有参数的时候,也可以直接把参数带上,就像这样:
<button @click="subAsync(5)"> +5 </button>
import {mapActions} from 'vuex'
//...省略一些代码
methods: {
...mapActions(['addAsync']),
},
模块化 + 命名空间
为什么使用模块化 ?
前言:如果在项目的store中只使用一个index.js文件去编写vuex逻辑用于管理数据的话,当数据多而复杂时,store 对象就有可能变得相当臃肿, 也不利于后期的维护。为了解决以上问题,Vuex 允许我们将 store 分割成
模块(module)
。每个模块拥有自己的 state、mutation、action、getter,当然如果你愿意的话,甚至还可以在模块中嵌套子模块。开启模块化的目的
:就是为了让代码更好维护,让多种数据分类更加明确。
namespaced: true 保证内部模块的高封闭性;
命名空间的概念
默认情况下,模块内部的 action、mutation 和 getter 是
注册在全局命名空间
的, 可以直接调用, 这样一来,不仅容易和其他模块, 同名state或者函数发生冲突,也很难让人直观得看出具体是在哪个子模块调用的。
所以在子模块的配置项目中, 必须添加 namespaced: true
属性来开启命名空间, 便于区分和其他模块及主模块中的同名状态或者函数, 防止冲突,开启后需要访问子模块中的内容就需要带模块名。
开启命名空间后如何使用?
1. state
- 插值表达式使用 :
$store.state.模块名.模块属性
- 在methods中调用
this.$store.state.模块名.模块属性
- 映射为辅助函数 - 数组格式:
...mapState('模块名', ['属性名'])
<template>
<view>
<!-- 插值表达式获取 -->
<text> {{ $store.state.order.price }} </text>
<!-- 计算属性获取 -->
<text> {{ myPrice }} </text>
<!-- 辅助函数之-数组形式 -->
<text> {{ {{ price }} }} </text>
</view>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
myPrice(){
return this.$store.state.order.price
},
...mapState('order', ['price'])
// ...mapState('order', ['price','count','list'])
}
}
</script>
*** 使用getters
-快捷访问 state
实际开发中, 以上方式较少用, 一般来说子模块中state里的数据, 都会在
主模块
中的getters写好, 方便获取。
- vuex中的getter , 可以认为是 store 的计算属性 ,和计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
- 实际开发中, 并不会使用子模块的getters, 因为它的存在本来就是给开发者提供快捷访问, 简化编码, 只有写在主模块中才能满足设计getters的出发点。
2. getter
- 插值表达式使用 :
$store.getter.[模块名/模块属性]
- 在methods中调用
this.$store.getters.[模块名/模块属性]
- 映射为辅助函数 - 数组格式:
...mapGetters('模块名', ['属性名'])
注意:这里是通过[模块名/模块属性]
获取,和上面的state是有区别的 !!
<template>
<view>
<!-- 插值表达式获取 -->
<text> {{ $store.getters['user/userinfo'] }} </text>
<!-- 计算属性获取 -->
<text> {{ myPrice }} </text>
<!-- 辅助函数之-数组形式 -->
<text> {{ {{ bigSum }} }} </text>
</view>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
myPrice(){
return this.$store.getters.order.price
},
...mapGetters('order',['bigSum'])
// ...mapGetters({myTxt: 'order/list'}),
}
}
</script>
3. action
- 触发方法 :
this.$store.dispatch('模块名/actions中的方法名', '实参')
- 在标签的事件上(如点击、滑动)触发
$store.dispatch('模块名/actions中的方法名', '实参')
- 映射为辅助函数 - 数组格式:
...mapActions(['模块名/actions中的方法名'])
在vuex中编写action
export default {
namespaced: true,
state :{
price:'998',
num:9999,
desc:{ txt:' 你好2018 !' }
},
actions : {
editTxt(context, payload){
context.commit("editTxt", payload)
},
},
mutations : {
editTxt(state, payload){
state.desc.txt = payload
}
},
getters : {}
}
在组件中触发action
<template>
<view>
<text> desc: {{ $store.state.order.desc.txt }} </text>
<button @click="clk1"> 把desc'你好2018 !'改成'你好2019 !'</button>
<button @click="clk2"> 把desc'你好2018 !'改成'你好2020 !'</button>
<button @click="clk3"> 把desc'你好2018 !'改成'你好2022 !'</button>
<!-- 点击按钮把desc'你好2018 !'改成'你好2021 !' -->
<button @click="$store.dispatch('order/editTxt', '你好2021 !')"> 更改 </button>
</view>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions({ aaa: 'order/editTxt'}),
clk1 () { this.aaa('你好2019 !')},
clk2 () {
this.$store.dispatch('order/editTxt', '你好2020 !')
},
...mapActions(['order/editTxt']),
clk3 () {
this['order/editTxt']('你好2022 !')
}
// ...mapActions('order',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
}
}
</script>
4. mutations
- 触发方法 :
this.$store.commit('模块名/actions中的方法名', '实参')
- 映射为辅助函数 - 数组格式:
...mapMutations(['模块名/actions中的方法名'])
在vuex中编写mutations
export default {
namespaced: true,
state :{
num:9999,
},
actions : {},
mutations : {
editNum(state, payload){
state.num = payload
}
},
getters : {}
}
在组件中触发mutations
<template>
<view>
<text> num9999 : {{ $store.state.order.num }} </text>
// 1.全局变量
<button @click="clk1"> 把num'9999'改成'1111'</button>
// 2.辅助函数-对象
<button @click="clk2"> 把num'9999'改成'2222'</button>
// 3.辅助函数-数组
<button @click="clk3"> 把num'9999'改成'3333'</button>
</view>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
methods: {
...mapMutations({ccc: 'order/editNum'}),
...mapMutations(['order/editNum']),
clk1(){
this.$store.commit('order/editNum',1111)
},
clk2(){ this.ccc(2222) },
clk3(){ this['order/editNum'](3333) }
}
}
</script>
更多推荐
所有评论(0)