Vue2项目中vuex如何简化程序代码,提升代码质量和开发效率

news2024/9/27 16:42:20

        Vuex为Vue中提供了集中式存储 + 库,其主要分为state、getter、mutation、action四个模块,它们每个担任了不同角色,分工不同;Vuex允许所有的组件共享状态抽取出来,以一个全局单例模式管理,状态集中存储在同一个地方,并且以相同的方式访问和修改。

        这样使得组件间的通信变的简单,组件之间不需要直接通信,只需要从Vuex的store中获取它们需要的数据即可。

        虽然Vuex在Vue中担任重要的角色,通过可预测化的状态管理模式来帮助开发者更好地管理复杂应用的状态。但是当遇到某些模块业务属性较多情况下,定义和管理也是相当繁琐,尤其是对其命名和调用,所以此时则需要通过有效地简化程序代码,来减少不必要的冗余,提升代码的整体质量。

一、Vuex的使用

        在Vue2中,关于vuex的安装和使用已写过一篇,有不了解可以前去查看,地址:Vue.js快速入门之二:使用状态管理工具Vuex_控制台输出vuex的数据-CSDN博客

        在这里,我们使用在store/index.js中定义userInfo和accessToken状态,代码如下:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

export default new Vuex.Store({
  // 定义属性
  state: {
    userInfo: '',
    accessToken: ''
  },
  // 定义计算属性
  getters: {
    user_info(state){
      return state.userInfo
    },
    access_token(state){
      return state.accessToken
    }
  },
  // 定义业务处理函数
  actions: {
    userInfoChange({commit}, value) {
      commit('USER_INFO_CHANGE', value)
    },
    accessTokenChange({commit}, value) {
      commit('ACCESS_TOKEN_CHANGE', value)
    }
  },
  // 定义属性裂变方法
  mutations: {
    USER_INFO_CHANGE(state, value) {
      state.userInfo = value
    },
    ACCESS_TOKEN_CHANGE(state, value){
      state.accessToken = value
    }
  }
});

       此时Vuex中则会出现这两个属性了,如下图:

二、较复杂业务状态管理

        对于比较常规的、属性较少的,且全局统一使用的可以定义在根节点,但对于某些特定业务或属性较多的,则需要单独定义一个子状态树去管理。

        在store目录中创建modules文件夹,用于创建和定义子模块业务的状态管理器。

        例如,商城App中,除了商品列表可以下单外,首页中精品推荐、热销商品等等商品展示位也可以点击下单。这样支付需要的信息,可以统一放到一个特定业务状态管理器中,做到集中管理。

        首先,创建modules/order.js用于处理订单业务模块。代码如下:

/**
 * 定义订单业务模块
 */
export default {
  state: {
    goodsName: '',    // 商品名称
    goodsPrice: 0,    // 商品价格
    goodsNumber: 0,   // 商品选择数量
    couponList: [],   // 使用 优惠券 列表
    freight: 0,       // 运费
    originPrice: 0,   // 原价格
  },
  getters: {
    goods_name(state) {
      return state.goodsName
    },
    goods_price(state) {
      return state.goodsPrice
    },
    goods_number(state) {
      return state.goodsNumber
    },
    coupon_list(state) {
      return state.couponList
    },
    // 优惠券价格之和
    coupon_use_price(state){
      return state.couponList.reduce((total, item) => total + item.price, 0)
    },
    coupon_number(state) {
      return state.couponList.length
    },
    freight_price(state) {
      return state.freight
    },
    origin_price(state) {
      return state.originPrice
    },
    // 计算支付价格
    pay_price(state) {
      return state.goodsPrice * state.goodsNumber + state.freight
    },
    // 计算应付金额
    total_price(state, getter) {
      return getter.pay_price - getter.coupon_use_price
    },
    // 节约成本
    cost_saving(state, getter) {
      return (state.originPrice * state.goodsNumber - getter.total_price).toFixed(1)
    }
  },
  actions: {
    // 更新属性参数
    orderInfoChange({commit}, params) {
      if('undefined' !== typeof params['goodsName']) commit('GOODS_NAME', params.goodsName)
      if('number' === typeof params['goodsPrice']) commit('GOODS_PRICE', params.goodsPrice)
      if('number' === typeof params['goodsNumber']) commit('GOODS_NUMBER', params.goodsNumber)
      if(params['couponList']&&Array.isArray(params['couponList'])) commit('COUPON_LIST', params.couponList)
      if('number' === typeof params['freight']) commit('FREIGHT', params.freight)
      if('number' === typeof params['originPrice']) commit('ORIGIN_PRICE', params.originPrice)
    }
  },
  mutations: {
    GOODS_NAME(state, value) {
      state.goodsName = value
    },
    GOODS_PRICE(state, value) {
      state.goodsPrice = value
    },
    GOODS_NUMBER(state, value) {
      state.goodsNumber = value
    },
    COUPON_LIST(state, value) {
      state.couponList = value
    },
    FREIGHT(state, value) {
      state.freight = value
    },
    ORIGIN_PRICE(state, value) {
      state.originPrice = value
    }
  }
}

        此时,vuex中状态树如下图:

        此时我们在页面中调用orderInfoChange业务方法,为状态管理器中添加点数据,再看看效果,代码如下:

<script>
export default {
  name: 'App',
  data(){
    return {}
  },
  created() {
    this.$store.dispatch('orderInfoChange', {
      goodsName: '红薯粉丝500g',    // 商品名称
      goodsPrice: 29.0,             // 商品价格
      goodsNumber: 10,              // 商品选择数量
      couponList: [
        {name: "券1", price: 0.5},
        {name: "券2", price: 1.2}
      ],
      freight: 20,                  // 运费
      originPrice: 32.5,            // 原价格
    })
  }
}
</script>

        如下图,只管将订单原始数据传入,通过Vuex对数据统一管理和集中业务处理,由Vuex完成数据计算、修改和输出,而不必在每个业务中单独计算,从而保证结果的一致性。

        在下单页面,直接取getters中的计算属性即可,当state中属性值改造后,其值也会实时更新为最新数据和数据合成结果。

三、精简模块内属性定义

        如上下单业务,是方便了各业务模块中,商品下单信息的统一管理和业务数据处理;但是对于四大模块中定义如此多属性和方法,随着项目中功能升级和信息增加,定义属性和方法越来越多,对后期管理和维护的工作量也是比较大的。

        对于此处,个人对Vuex有一些见解,通过程序自动完成部分属性和方法的定义,来简化流程。状态管理中,getters和actions的计算属性和业务层较多,而state和mutations则比较单一,所以这里将利用state,通过函数方法自动完成相关属性和函数的定义,再将其结果还原到状态树中。

 第一步:在utils/utils.js文件中定义useStateAndMutations()函数,用于重构状态树中需要的属性和方法。代码如下:

/**
 * 驼峰转下划线
 */
const camelCaseToSnakeCase = str => {
  return str.replace(/\B(?=[A-Z])/g, '_')
}

/**
 * 构建state与mutations,以commit执行类型常量
 */
export const useStateAndMutations = (CONST_PARAMS) => {
  // 重构数据
  const list = Object.keys(CONST_PARAMS).map(item => {
    return {
      origin: item,                                     // 原始值
      upper: camelCaseToSnakeCase(item).toUpperCase(),  // 下划线 - 大写
      snake: camelCaseToSnakeCase(item).toLowerCase()   // 下划线 - 小写
    }
  })
  // mutationTypes 常量定义
  const mutationTypes = list.reduce(
    (obj, item) => Object.assign(obj, { [item.upper]: item.origin }),
    {}
  );
  // getters 计算属性定义(如果直接使用state数据,则此部分可以忽略)
  const getters = list.reduce(
    (obj, item) => Object.assign(obj, { [item.snake](state){ return state[item.origin] } }),
    {}
  )
  // mutations 定义
  const mutations = list.reduce(
    (obj, item) => Object.assign(obj, { [item.origin](state, value){ state[item.origin] = value } }),
    {}
  )
  // 对外暴露 生产出来的数据
  return { mutationTypes, getters, mutations }
}

第二步:将@/utils/utils.js引入到order.js文件中,然后通过useStateAndMutations()解构出mutationTypes, getters, mutations,并将getters和mutations还原到状态树中。代码如下:

import { useStateAndMutations } from '@/utils/utils'
// 定义state属性
const useState = {
  goodsName: '',    // 商品名称
  goodsPrice: 0,    // 商品价格
  goodsNumber: 0,   // 商品选择数量
  couponList: [],   // 使用 优惠券 列表
  freightPrice: 0,  // 运费
  originPrice: 0,   // 原价格
}
// 执行构建函数
const { mutationTypes, getters, mutations } = useStateAndMutations(useState)

/**
 * 定义订单业务模块
 */
export default {
  state: useState,
  getters: {
    ...getters,
    // 优惠券价格之和
    coupon_use_price(state){
      return state[mutationTypes.COUPON_LIST].reduce((total, item) => total + item.price, 0)
    },
    coupon_number(state) {
      return state[mutationTypes.COUPON_LIST].length
    },
    // 计算支付价格
    pay_price(state) {
      return state[mutationTypes.GOODS_PRICE] * state[mutationTypes.GOODS_NUMBER] + state[mutationTypes.FREIGHT_PRICE]
    },
    // 计算应付金额
    total_price(state, getter) {
      return getter.pay_price - getter.coupon_use_price
    },
    // 节约成本
    cost_saving(state, getter) {
      return (state[mutationTypes.ORIGIN_PRICE] * state[mutationTypes.GOODS_NUMBER] - getter.total_price).toFixed(1)
    }
  },
  actions: {
    // 更新属性参数
    orderInfoChange({commit}, params) {
      if('undefined' !== typeof params[mutationTypes.GOODS_NAME]) 
        commit(mutationTypes.GOODS_NAME, params[mutationTypes.GOODS_NAME])
      if('number' === typeof params[mutationTypes.GOODS_PRICE]) 
        commit(mutationTypes.GOODS_PRICE, params[mutationTypes.GOODS_PRICE])
      if('number' === typeof params[mutationTypes.GOODS_NUMBER]) 
        commit(mutationTypes.GOODS_NUMBER, params[mutationTypes.GOODS_NUMBER])
      if(params[mutationTypes.COUPON_LIST]&&Array.isArray(params[mutationTypes.COUPON_LIST])) 
        commit(mutationTypes.COUPON_LIST, params[mutationTypes.COUPON_LIST])
      if('number' === typeof params[mutationTypes.FREIGHT_PRICE]) 
        commit(mutationTypes.FREIGHT_PRICE, params[mutationTypes.FREIGHT_PRICE])
      if('number' === typeof params[mutationTypes.ORIGIN_PRICE]) 
        commit(mutationTypes.ORIGIN_PRICE, params[mutationTypes.ORIGIN_PRICE])
    }
  },
  mutations
}

        此时再看order.js文件中代码,已经明显减少了很多代码,最终Vuex状态管理器中属性结构还是和之前一样,如下图:

        输出mutationTypes, getters, mutations三个结果,大家可能会比较好理解useStateAndMutations()方法到底做了什么,如下图:

        通过useStateAndMutations()方法,只需两步操作,就将本该手动定义的常量、计算属性和修改属性值(裂变)方法,用state属性中的key值来完成,从而简化操作。

四、orderInfoChange优化

        在orderInfoChange方法中,大家可能看的眼花缭乱,但可以看出都是通过mutationTypes常量值来取值的,所以通过以下代码,对代码进行分类处理和优化,从而简化并能更好理解。

actions: {
	// 更新属性参数
	orderInfoChange({commit}, params) {
	  if('undefined' === typeof params) return;
	  // 字符串数据处理
	  [mutationTypes['GOODS_NAME']].forEach(key => {
		if('string' === typeof params[key]) commit(key, params[key])
	  });
	  // number数据处理
	  [
        mutationTypes.GOODS_PRICE, 
        mutationTypes.GOODS_NUMBER, 
        mutationTypes.FREIGHT_PRICE, 
        mutationTypes.ORIGIN_PRICE
      ].forEach(key => {
		if('number' === typeof params[key]) commit(key, params[key])
	  });
	  // 数组数据处理
	  [mutationTypes.COUPON_LIST].forEach(key => {
		if(params[key]&&Array.isArray(params[key])) commit(key, params[key])
	  });
	}
}

        进行调整后,商品信息传入orderInfoChange中后,数据依然正常赋值及裂变,如下图:

        综上所述,我们在JavaScript开发中,可以简化程序代码和减少不必要的冗余代码,来提高代码质量、可维护性和可读性。函数式编程中,利用高阶函数(如map、filter、reduce等数组方法)和纯函数来简化对数组和集合的操作;编写可复用的函数,避免重复代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2170484.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安装软件及apt install -f修复均报错

UOS统信安装软件过程及修复依赖过程&#xff0c;可排查deepin-installer和dpkg问题 文章目录 一、问题现象二、问题原因三、解决方案 一、问题现象 执行apt install -f 都会出现该报错&#xff0c;如图所示&#xff1a; 二、问题原因 造成这种情况的原因在于/var/lib/dpkg/…

视频生成模型哪家强?豆包可灵通义海螺全面评测【AI评测】

比较贴切的表述是&#xff0c;豆包的视频模型这次的升级&#xff0c;已然将国内AI视频的美学境界拔高了一个档次&#xff0c;让AI视频也开始变得更加实用了。 作者|斗斗 出品|产业家 国内的文生视频领域&#xff0c;也是吃上“细糠”了。 最近&#xff0c;火山引擎宣布豆…

必收藏,售后客服日常回复必备的话术 (精华版)

在售后客服工作中&#xff0c;使用恰当的话术对客户进行回复至关重要。本文精选了售后客服日常工作中必备的精华话术&#xff0c;旨在帮助客服人员提升回复效率和服务质量。其中包括客户投诉处理、问题解决、礼貌用语等多个方面的话术内容。 前言 在售后客服工作中&#xff0c…

Flux【lora模型】【禅意插画】:画风清新唯美,充满禅意韵味的插画模型:Zenpainting l 禅意插画

大家好我是安琪&#xff01;&#xff01;&#xff01; 今天和大家推荐一款基于Flux训练的禅意插画风格的lora模型:Zenpainting l 禅意插画**。**此Lora模型可生成富禅意韵味的艺术插画&#xff0c;画风清新唯美&#xff0c;充满艺术意境。 提示词&#xff1a;Zen painting il…

URI和URL的区别

1: 将 URI 转换为 URL import java.net.URI; import java.net.URL;public class UriToUrlExample {public static void main(String[] args) {// 创建一个 URI 对象URI uri = new URI("http://example.com/path/to/resource");// 将 URI 转换为 URLtry {URL url = u…

C++:模板(1)

目录 实现泛型的交换函数 函数模板 1.概念 2.格式 3.原理 4.函数模板实例化 5.函数模板参数的匹配原则 类模板 1.定义格式 2.实例化 3.声明与定义问题 实现泛型的交换函数 我们实现一个对所有类型都通用的交换函数&#xff0c;可以用函数重载来实现。 void Swap(in…

Map和Set,TreeMap和TreeSet,HashMap和HashSet

文章目录 TreeSet和TreeMap二叉搜索树模拟TreeMAp定义 基本操作插入查找删除(难点)遍历性能分析应用场景 Map&&Set模型 HashMap常用方法 HashSet常用方法HashMap和HashSet区别数据结构不同元素类型不同方法不同使用场景不同 TreeSet和TreeMap 定义&#xff1a; TreeSe…

个人健康档案管理系统

基于springbootvue实现的个人健康档案管理系统&#xff08;源码L文ppt&#xff09;4-076 4.1 系统功能结构设计 根据对个人健康档案管理系统的具体需求分析&#xff0c;把系统可以划分为几个不同的功能模块&#xff1a;管理员可以对系统首页、用户管理、健康体检管理、疫…

智能密码、指纹锁语音芯片ic方案 可存放40s语音内容 NVD语音芯片

随着科技的飞速发展&#xff0c;智能家居安全领域迎来了前所未有的变革。智能密码与指纹锁作为现代家庭安全防护的重要一环&#xff0c;其背后的语音芯片IC开发更是这一变革中的关键技术突破。 智能密码、指纹锁语音芯片ic方案 选型与简介&#xff1a; NVD语音芯片是一款低成…

基于JAVA+SpringBoot+Vue的疫苗发布和接种预约系统

基于JAVASpringBootVue的疫苗发布和接种预约系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f3…

AlmaLinux 安裝JDK8

在 AlmaLinux 上安装 JDK 8 可以通过包管理器 dnf 来完成。AlmaLinux 是基于 RHEL 的一个开源发行版&#xff0c;因此其包管理系统和 RHEL 类似。以下是详细的步骤来安装 OpenJDK 8 1. 更新系统包列表 sudo dnf update -y 2. 安装 OpenJDK 8 使用 dnf 安装 OpenJDK 8。你可…

【Python-tkinter】实现简单的文本编辑器(附带教程源码)

如果你也是刚入门的小伙伴呢&#xff0c;小编为你们准备了入门Python学习籽料和Python入门实践&#xff0c;点击领取&#xff08;无偿获得&#xff09; 利用tkinter实现简单的文本编辑器。创建一个简单的文本编辑器。可以用读文件的方式在一个文本域里显示一些文字供用户编辑…

大模型分布式训练并行技术(七)-自动并行

近年来&#xff0c;随着Transformer、MOE架构的提出&#xff0c;使得深度学习模型轻松突破上万亿规模参数&#xff0c;传统的单机单卡模式已经无法满足超大模型进行训练的要求。因此&#xff0c;我们需要基于单机多卡、甚至是多机多卡进行分布式大模型的训练。 而利用AI集群&a…

5--苍穹外卖-SpringBoot项目中菜品管理 详解(一)

目录 公共字段自动填充 问题分析 实现思路 代码开发 步骤一 步骤二 功能测试 新增菜品 需求分析和设计 代码开发 文件上传接口 功能测试 1--苍穹外卖-SpringBoot项目介绍及环境搭建 详解-CSDN博客 2--苍穹外卖-SpringBoot项目中员工管理 详解&#xff08;一&#…

医疗器械库存管理软件 符合gsp要求

软件介绍&#xff1a; 盘谷医疗器械进销存管理软件契合医疗器械行业特点&#xff0c;符合gsp要求&#xff0c;专为一二三类医疗器械经营企业开发的医疗器械进销存、质量验收、GSP管理、UDI扫码识别、财务管理一体化经营管理系统&#xff0c;符合药监新版医疗器械经营质量管理规…

C++在线开发环境搭建(WEBIDE)

C在线开发环境搭建 一、环境说明1.1 系统基础环境说明1.1 docker-ce社区版安装 二、codeserver构建2.1 构建codeserver环境的docker容器2.2 构建docker镜像2.3 运行docker2.4 运行展示 三、构建codeserver中的c开发环境3.1 插件下载3.2 插件安装 四、其他知识4.2 code-server配…

vue仿chatGpt的AI聊天功能--大模型通义千问(阿里云)

vue仿chatGpt的AI聊天功能–大模型通义千问&#xff08;阿里云&#xff09; 通义千问是由阿里云自主研发的大语言模型&#xff0c;用于理解和分析用户输入的自然语言。 1. 创建API-KEY并配置环境变量 打开通义千问网站进行登录&#xff0c;登陆之后创建api-key&#xff0c;右…

20个数字经济创新发展试验区建设案例【2024年发布】

数据简介&#xff1a;国家数字经济创新发展试验区的建设是一项重要的国家战略&#xff0c;旨在推动数字经济与实体经济的深度融合&#xff0c;促进经济高质量发展。自2019年10月启动以来&#xff0c;包括河北省&#xff08;雄安新区&#xff09;、浙江省、福建省、广东省、重庆…

【java】前端RSA加密后端解密

目录 1. 说明2. 前端示例3. 后端示例3.1 pom依赖3.2 后端结构图3.3 DecryptHttpInputMessage3.4 ApiCryptoProperties3.5 TestController3.6 ApiCryptoUtil3.7 ApiDecryptParamResolver3.8 ApiDecryptRequestBodyAdvice3.9 ApiDecryptRsa3.10 ApiCryptoProperties3.11 KeyPair3…

一天面了8个Java后端,他们竟然还在背5年前的八股文!

今天面了8个Java候选人&#xff0c;在面试中我发现他们还停留在面试背八股文的阶段&#xff0c;5年前面试背八股文没问题&#xff0c;随着市场竞争越来越激烈&#xff0c;再问普通的Java八股文已经没有意义了&#xff0c;因为考察不出来获选人的真实实力&#xff01; 现在面试…