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

QQ截图20211114171546

state 数据源

state 提供唯一的公共数据源,所有共享的数据都要统一放到 Storestate 中进行存储。

使用方式
  1. 插值表达式获取 <view>{{$store.state.count}}</view>
  2. 在methods中直接使用state this.$store.state.count
  3. 如果开启了模块化:this.$store.state.模块名.模块属性,使用插值表达式时可以省略this。
  4. 使用计算属性获取
    • 未开启模块化: ...mapState(['模块名'])
    • 开启模块化后使用方式:...mapState(['模块名'],['属性名'])
示例:
直接使用

直接在组件中的computedmethods中使用 :


<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的方式间接变更数据

  1. 在 actions 使用commit('mutations中的方法名',数据)触发 mutation。
  2. 在组件中触发 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中的数据进行加工处理形成新的数据。筛选或者排序显示。

  1. Getter 不会修改 Store 中的原数据,它只起到一个包装器的作用,将Store中的数据加工后输出出来。
  2. 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
  1. 插值表达式使用 : $store.state.模块名.模块属性
  2. 在methods中调用 this.$store.state.模块名.模块属性
  3. 映射为辅助函数 - 数组格式: ...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
  1. 插值表达式使用 : $store.getter.[模块名/模块属性]
  2. 在methods中调用 this.$store.getters.[模块名/模块属性]
  3. 映射为辅助函数 - 数组格式: ...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
  1. 触发方法 : this.$store.dispatch('模块名/actions中的方法名', '实参')
  2. 在标签的事件上(如点击、滑动)触发 $store.dispatch('模块名/actions中的方法名', '实参')
  3. 映射为辅助函数 - 数组格式: ...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
  1. 触发方法 : this.$store.commit('模块名/actions中的方法名', '实参')
  2. 映射为辅助函数 - 数组格式: ...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>
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐