当前位置: 首页 > ops >正文

二次封装 Vuex for Uniapp 微信小程序开发

作为高级前端开发工程师,我将为你提供一个针对 Uniapp + Vue2 + Vuex 的 Store 二次封装方案,使团队成员能够更便捷地使用和管理状态。

封装目标

  1. 模块化管理状态

  2. 简化调用方式

  3. 提供类型提示(在 Vue2 中尽可能实现)

  4. 便于维护和查找

封装方案

1. 目录结构重构

首先,我们重构 store 的目录结构:

store/
├── index.js              # 主入口文件
├── modules/              # 模块目录
│   ├── user.js           # 用户模块
│   ├── cart.js           # 购物车模块
│   └── ...               # 其他模块
└── store-utils.js        # 封装的工具方法

 2. 主入口文件封装 (store/index.js)

import Vue from 'vue'
import Vuex from 'vuex'
import * as utils from './store-utils'Vue.use(Vuex)// 自动加载 modules 目录下的所有模块
const modules = utils.autoLoadModules()const store = new Vuex.Store({modules,// 全局配置strict: process.env.NODE_ENV !== 'production'
})// 挂载工具方法到 Vue 原型
Vue.prototype.$storeUtils = utilsexport default store

3. 工具方法封装 (store/store-utils.js)

/*** 自动加载 modules 目录下的所有模块*/
export function autoLoadModules() {const modules = {}const requireModule = require.context(// 搜索目录'./modules',// 是否搜索子目录false,// 匹配文件的正则/\.js$/)requireModule.keys().forEach(fileName => {// 获取模块名(去掉文件扩展名)const moduleName = fileName.replace(/(\.\/|\.js)/g, '')modules[moduleName] = {namespaced: true,...requireModule(fileName).default}})return modules
}/*** 简化 mapState 调用* @param {string} moduleName 模块名* @param {Array|Object} states 状态名数组或对象*/
export function mapState(moduleName, states) {if (!moduleName) return {}if (Array.isArray(states)) {const result = {}states.forEach(key => {result[key] = function() {return this.$store.state[moduleName][key]}})return result}// 对象形式const result = {}Object.keys(states).forEach(key => {result[key] = function() {return this.$store.state[moduleName][states[key]]}})return result
}/*** 简化 mapGetters 调用* @param {string} moduleName 模块名* @param {Array|Object} getters getter名数组或对象*/
export function mapGetters(moduleName, getters) {if (!moduleName) return {}const namespace = moduleName + '/'if (Array.isArray(getters)) {const result = {}getters.forEach(getterName => {result[getterName] = function() {return this.$store.getters[namespace + getterName]}})return result}// 对象形式const result = {}Object.keys(getters).forEach(key => {result[key] = function() {return this.$store.getters[namespace + getters[key]]}})return result
}/*** 简化 mapMutations 调用* @param {string} moduleName 模块名* @param {Array|Object} mutations mutation名数组或对象*/
export function mapMutations(moduleName, mutations) {if (!moduleName) return {}const namespace = moduleName + '/'if (Array.isArray(mutations)) {const result = {}mutations.forEach(mutationName => {result[mutationName] = function(payload) {this.$store.commit(namespace + mutationName, payload)}})return result}// 对象形式const result = {}Object.keys(mutations).forEach(key => {result[key] = function(payload) {this.$store.commit(namespace + mutations[key], payload)}})return result
}/*** 简化 mapActions 调用* @param {string} moduleName 模块名* @param {Array|Object} actions action名数组或对象*/
export function mapActions(moduleName, actions) {if (!moduleName) return {}const namespace = moduleName + '/'if (Array.isArray(actions)) {const result = {}actions.forEach(actionName => {result[actionName] = function(payload) {return this.$store.dispatch(namespace + actionName, payload)}})return result}// 对象形式const result = {}Object.keys(actions).forEach(key => {result[key] = function(payload) {return this.$store.dispatch(namespace + actions[key], payload)}})return result
}/*** 创建模块的快捷访问方式* @param {string} moduleName 模块名*/
export function createModuleHelpers(moduleName) {return {state: (stateName) => {return this.$store.state[moduleName][stateName]},getter: (getterName) => {return this.$store.getters[`${moduleName}/${getterName}`]},commit: (mutationName, payload) => {this.$store.commit(`${moduleName}/${mutationName}`, payload)},dispatch: (actionName, payload) => {return this.$store.dispatch(`${moduleName}/${actionName}`, payload)}}
}

4. 模块示例 (store/modules/user.js)

const state = {token: '',userInfo: null,isLogin: false
}const getters = {getUserName: state => {return state.userInfo?.name || ''},getUserId: state => {return state.userInfo?.id || ''}
}const mutations = {SET_TOKEN(state, token) {state.token = token},SET_USER_INFO(state, userInfo) {state.userInfo = userInfostate.isLogin = !!userInfo},CLEAR_USER(state) {state.token = ''state.userInfo = nullstate.isLogin = false}
}const actions = {login({ commit }, { username, password }) {return new Promise((resolve, reject) => {// 模拟登录请求uni.request({url: '/api/login',method: 'POST',data: { username, password },success: (res) => {commit('SET_TOKEN', res.data.token)commit('SET_USER_INFO', res.data.userInfo)resolve(res.data)},fail: (err) => {reject(err)}})})},logout({ commit }) {commit('CLEAR_USER')return Promise.resolve()}
}export default {state,getters,mutations,actions
}

使用方式

1. 组件中使用

import { mapState, mapGetters, mapMutations, mapActions } from '@/store/store-utils'export default {computed: {// 传统方式...mapState('user', ['token', 'userInfo', 'isLogin']),...mapGetters('user', ['getUserName', 'getUserId']),// 或者使用对象形式...mapState('user', {myToken: 'token',myUserInfo: 'userInfo'})},methods: {...mapMutations('user', ['SET_USER_INFO']),...mapActions('user', ['login', 'logout']),// 示例方法handleLogin() {this.login({ username: 'test', password: '123456' }).then(() => {uni.showToast({ title: '登录成功' })}).catch(err => {uni.showToast({ title: '登录失败', icon: 'none' })})}}
}

2. 快捷访问方式

export default {methods: {someMethod() {// 使用快捷访问const userHelpers = this.$storeUtils.createModuleHelpers('user')// 获取状态const token = userHelpers.state('token')// 获取getterconst userName = userHelpers.getter('getUserName')// 提交mutationuserHelpers.commit('SET_USER_INFO', { name: '张三' })// 分发actionuserHelpers.dispatch('logout').then(() => {console.log('登出成功')})}}
}

3. 在JS文件中使用

import store from '@/store'// 直接使用store
const token = store.state.user.token// 提交mutation
store.commit('user/SET_TOKEN', 'new-token')// 分发action
store.dispatch('user/login', { username: 'test', password: '123456' }).then(() => {console.log('登录成功')})

最佳实践建议

  1. 命名规范

    • 模块名使用小驼峰命名法 (user, shoppingCart)

    • state 属性使用小驼峰命名法

    • mutations 使用大写蛇形命名法 (SET_USER_INFO)

    • actions 使用小驼峰命名法

  2. 文档注释
    在每个模块文件顶部添加注释说明模块用途,重要的 state、getter、mutation 和 action 添加注释

  3. 模块拆分

    • 按业务功能拆分模块

    • 避免单个模块过大

http://www.xdnf.cn/news/9194.html

相关文章:

  • linux如何查看网络设备类型
  • 学者观察 | Web3.0的技术革新与挑战——北京理工大学教授沈蒙
  • 机器学习中的关键术语及其含义
  • 打造自己的开源组件:如何将 Starter 发布到 Maven Central?
  • 人工智能100问☞第34问:什么是语音识别与合成?
  • xilinx 7系列底层可配置逻辑块CLB资源简介
  • js 实现多并发任务处理
  • AI时代的弯道超车之第二十一章:AI会颠覆哪些行业?
  • 什么是MCP技术,跟http技术有什么区别
  • Excel 统计某个字符串在指定区域出现的次数
  • 低空经济管理系统设计方案
  • Spring Boot 3.4.6 中文文档上线
  • 深入理解 JDK、JRE 和 JVM 的区别
  • CellularPro 1.8.6.1 | 提升网络速度,抢到更多基站的速度
  • Netty创新架构突破链接数瓶颈技术,如何应用于新能源汽车智慧充电桩?
  • Redis 容器启动失败Fatal error loading the DB, check server logs. Exiting.的解决方法
  • 使用 ssld 提取CMS 签名并重签名
  • 在PyTorch中,有了y = x + y,为什么还需要y += x,有什么好处呢?
  • 九级融智台阶的要素协同跃迁框架
  • 6个月Python学习计划 Day 6 - 综合实战:学生信息管理系统
  • ai写歌平台:AnKo开启音乐创作的智能时代!
  • java类加载器
  • 树莓派超全系列教程文档--(50)如何查找树莓派的IP地址
  • 计算机组成与体系结构:硬盘驱动器(Hard Disk Drives)
  • OpenGL Chan视频学习-9 Index Buffers inOpenGL
  • STM32F407VET6学习笔记6:定时器TIM2的配置使用
  • MPLS实验复现
  • 70页精品PPT | 休闲食品行业数据分析平台建设方案快消BI大数据解决方案BI方案
  • [ Qt ] | 常用控件(三):
  • AR眼镜+AI视频盒子+视频监控联网平台:消防救援的智能革命