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

news/2024/9/28 1:14:31 标签: javascript, 前端, vue.js

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

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

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

一、Vuex的使用

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

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

javascript">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用于处理订单业务模块。代码如下:

javascript">/**
 * 定义订单业务模块
 */
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业务方法,为状态管理器中添加点数据,再看看效果,代码如下:

javascript"><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()函数,用于重构状态树中需要的属性和方法。代码如下:

javascript">/**
 * 驼峰转下划线
 */
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还原到状态树中。代码如下:

javascript">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常量值来取值的,所以通过以下代码,对代码进行分类处理和优化,从而简化并能更好理解。

javascript">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.niftyadmin.cn/n/5680008.html

相关文章

基于Hive和Hadoop的电商消费分析系统

本项目是一个基于大数据技术的电商消费分析系统&#xff0c;旨在为用户提供全面的电商消费信息和深入的消费行为分析。系统采用 Hadoop 平台进行大规模数据存储和处理&#xff0c;利用 MapReduce 进行数据分析和处理&#xff0c;通过 Sqoop 实现数据的导入导出&#xff0c;以 S…

C++系列-STL容器中算法中的最大最小

STL容器中算法中的最大最小 最大最小相关算法最大最小相关示例 最大最小相关算法 算法名称描述max(a, b)返回两个元素中较大的一个&#xff0c;return _Left < _Right ? _Right : _Left;max(a, b, pred)使用谓词作大小比较&#xff0c;return _Pred(_Left, _Right) ? _Ri…

为广大星商赋能,长沙还真是下足了功夫

随着城市竞争加剧&#xff0c;城市之间不仅要比拼上市公司数量&#xff0c;还要比拼初创企业的质量。建立更科学、有效的企业培育机制&#xff0c;真正给予企业发展所需要的帮助&#xff0c;将成为一座城市吸引年轻人和创业者的强大竞争力。 前段时间&#xff0c;笔者在与朋友…

信息学奥赛的最佳启蒙阶段是小学还是初中?

信息学奥赛&#xff08;NOI&#xff09;近年来越来越受家长和学生的关注&#xff0c;尤其是在编程教育不断升温的背景下&#xff0c;信息学竞赛成为了许多家庭的教育选择之一。家长们往往关心的是&#xff1a;孩子应该在什么年龄段开始接触信息学竞赛&#xff0c;才能打下坚实的…

数据结构基础之《(4)—异或运算》

一、认识异或运算 1、异或运算 相同为0&#xff0c;不同为1 2、同或运算 相同为1&#xff0c;不同为0 3、异或记成无进位相加&#xff01; 二、例子 1、6 ^ 7 ? 解答&#xff1a;110 ^ 111 001 三、异或运算的性质 1、0 ^ N N 2、N ^ N 0 3、异或运算满足交换律和结…

如何创建AWS云账号

引言 Amazon Web Services (AWS) 是全球领先的云计算平台&#xff0c;提供广泛的云服务&#xff0c;包括计算、存储、数据库、分析、机器学习等。要开始使用AWS&#xff0c;首先需要创建一个AWS账号。本文中九河云将详细介绍如何创建AWS云账号&#xff0c;并提供一些最佳实践和…

树上前缀和详解

零、前言 关于前缀和&#xff1a; 前缀和详解&#xff0c;朴素前缀和&#xff0c;前缀和变形&#xff0c;二维前缀和_前缀积-CSDN博客 关于LCA&#xff1a; LCA算法-倍增算法_lca倍增算法-CSDN博客 LCA算法-Tarjan算法_lca数组-CSDN博客 树链剖分——重链剖分&#xff0c…

同声传译用什么软件最方便?推荐五款易用的同声传译软件

在国际贸易、国际会议及跨国合作项目中&#xff0c;语言障碍往往是沟通效率的一大挑战。 为了解决这个问题&#xff0c;同声传译免费软件应运而生&#xff0c;它们通过先进的技术实现了即时准确的语言转换&#xff0c;极大地促进了不同语言使用者间的交流与协作。 下面&#…