Vue项目中的字段格式化工具(进阶版)

场景: 对于一些全局公用的状态,或是字典,甚至是后端枚举,为了方便维护,我们应尽量使它们全局公用,但我们在开发往往会忽略这个问题,总想着后面再改,可随着项目的不断推进,我们往往都视之不理。
功能: 解决vue项目中字段、字典、状态类全局维护问题。
优势: 一次配置全局公用、可单独变更、可自定义、低请求、方便、快捷。
特点: 组件化、全局化、公用化。

1. 创建组件

components 下创建 FieldFormat 包,然后在该包下创建 index.vue

2. 创建基础属性类

该类为所有属性类的基类,也用以规范属性列表。

FieldFormat 包下创建 Base.js,内容如下:

export default class Base {constructor() {this.serve = undefined;this.id = undefined;this.label = undefined;this.method = 'get';this.dataField = 'data';this.isEnum = false;this.isDict = false;this.isCustom = false;this.customData = undefined;this.render = undefined;this.tagTypes = undefined;}/*** 添加tag属性,用以匹配el-tag样式* @param tags* @returns {Base}*/tags(tags) {this.tagTypes = tags;return this;}/*** 添加自定义渲染,传入函数,将渲染返回的内容* @param render* @returns {Base}*/renders(render) {this.render = render;return this;}
}

3. 创建自定义数据类

该类为自定义数据属性,可传入自定义的属性用于匹配字段。

FieldFormat 包下创建 Custom.js,内容如下:

import Base from "./Base";/*** 自定义数据*/
export default class Custom extends Base {constructor(data, id, label) {super();this.customData = data;this.isCustom = true;this.id = id;this.label = label;}
}

4. 创建可扩展属性类

该类用于自定义请求、字段等属性,扩展性高。

FieldFormat 包下创建 Field.js,内容如下:

import Base from "./Base";/*** 字段,用以匹配后端字段*/
export default class Field extends Base {constructor(serve, id, label, method, dataField) {super();this.serve = serve;this.id = id;this.label = label;if (method) {this.method = method;}if (dataField) {this.dataField = dataField;}}
}

5. 创建字典类

该类用于定义字典属性列表,用于匹配字典数据。

FieldFormat 包下创建 Dict.js,内容如下:

import Base from "./Base";/*** 字典,用以匹配后端字典*/
export default class Dict extends Base {constructor(serve) {super();this.serve = serve;this.id = "dictValue";this.label = "dictLabel";this.isDict = true;}
}

6. 创建后端枚举类

该类用于定义枚举属性列表,用于匹配后端枚举数据。

FieldFormat 包下创建 Enum.js,内容如下:

import Base from "./Base";/*** 枚举,根据name字段匹配*/
export default class Enum extends Base {constructor(serve) {super();this.id = "name";this.label = "description";this.isEnum = true;this.serve = serve;}
}

7. 创建格式化类型列表

创建 formatOptions.js,内容如下(仅提供部分参考,依个人需求变更):

import * as vehicleTypeService from "@/api/bayonet/vehicleType";
import Enum from "./Enum";
import Dict from "./Dict";
import Field from "./Field";
import Custom from "./Custom";// 枚举路径前缀
const pathBayonetPrefix = "com.jl15988.project.bayonet.enums.";
const pathApplicationPrefix = "com.jl15988.project.application.enums.";/*** 字段格式化组件参数** @param serve 请求地址或请求方法或枚举类型,请求方法可以是api中的,必须是Function: () => Promise格式* @param id 请求后的数据列表字段,用于匹配那一条数据* @param label 请求后的数据列表字段,用于自动格式化字段* @param method 请求方式,默认get* @param dataField 请求后的data字段,默认data* @param isEnum 是否枚举,开启将请求后端枚举* @param isDict 是否字典,开启将请求后端字典* @param isCustom 是否自定义,开启自定义数据模式* @param customData 自定义的数据* @param render 用于自定义渲染操作,参数为(data, list),data为当前数据项,list为全部数据列表*/
export default {// 车辆类型。普通的拓展属性vehicleType: new Field(vehicleTypeService.getList, "vehicleTypeId", "name"),// 车辆类型(全路径)。自定义渲染的拓展属性vehicleTypeFull: new Field(vehicleTypeService.listAll, "vehicleTypeId", "name").renders((data, list) => {// 这里可以通过 data、list 参数来完成个人需要的格式。下面是根据节点ID,拼完整的类型。if (!data || !data.name) {return "";}const names = [data.name];findParent(data);function findParent(row) {if (!row.parentId) {return;}const vehicleType = list.find(item => item.vehicleTypeId === row.parentId);if (vehicleType && vehicleType.name) {names.push(vehicleType.name);}if (vehicleType && list.filter(item => item.vehicleTypeId === vehicleType.parentId).length > 0) {findParent(vehicleType);}}names.reverse();return names.join("/");}),// 审批状态。枚举属性approvalStatusEnum: new Enum(pathApplicationPrefix + "ApprovalStatus")// 通过定义 tag 可以实现显示 el-tag 样式.tags({"10": "", // 待审核"20": "info","30": "warning", // 企业驳回"40": "success", // 已通过"50": "warning", // 已驳回"60": "danger" // 停运}),// 车辆是否进入。字典属性vehicle_enter_status: new Dict("vehicle_enter_status").tags({"0": "","1": "success"}),// 异常车辆状态。自定义属性abnormalVehicleStatus: new Custom({"0": "正常","1": "异常"}).tags({"0": "success","1": "danger"})
}

8. 修改组件

将 index.vue 改为一下内容:

<template><span><template v-if="!hasSlot && !tag && !tags && !tagTypes">{{ labelValue }}</template><el-tag v-if="!hasSlot && labelValue && (tag || tags || tagTypes)" :type="tagType">{{ labelValue }}</el-tag><slot></slot><slot name="format" :data="data"></slot><slot name="list" :list="list"></slot></span>
</template><script>
import {cacheGet, cachePost} from '@/utils/request';
import formatOptions from "./formatOptions";export default {name: "FieldFormat",props: {/*** 用于匹配的值*/value: [String, Number],/*** 要格式化的类型*/type: String,/*** 发起请求的额外参数*/params: Object,/*** 没有匹配的数据时,代替显示的内容*/alternate: String,/*** 关闭Tag标签样式*/closeTag: Boolean,/*** 要显示的Tag标签样式(默认的为default),见Element文档*/tag: String,/*** 按数据显示的Tag标签样式,数据值为key,样式为值*/tags: Object},data() {return {enumUrl: 'common/utility/getEnumList',dictUrl: 'system/dict/data/dictType/',data: undefined,list: [],serve: undefined,id: undefined,label: undefined,method: 'get',dataField: 'data',isEnum: false,isDict: false,isCustom: false,customData: undefined,render: undefined,tagTypes: undefined}},computed: {fieldFormats() {// 获取vuex中缓存的数据return this.$store.state.fieldFormat.types;},hasSlot() {// 判断有没有插槽(默认插槽除外)return (this.$scopedSlots && (!!this.$scopedSlots.list || !!this.$scopedSlots.format))|| (this.$slots && (!!this.$slots.list || !!this.$slots.format));},labelValue() {if (this.render) {return this.render(this.data, this.list);} else if (this.isCustom && !this.id) {return this.customData[this.value];} else if (this.data && this.label) {return this.data[this.label];} else {return this.alternate;}},tagType() {if (this.closeTag) {return "";}if (this.tag) {return this.tag;} else if (this.tags) {return this.tags[this.value];} else if (this.tagTypes) {return this.tagTypes[this.value];} else {return "";}}},watch: {type: {handler(n) {// 类型改变时重新获取数据this.getData();}},value: {handler(n) {// 值改变时重新解析this.format();}}},methods: {/*** 解析*/format() {// 在列表中查找对应数据if (this.isCustom && this.id) {this.list = this.customData;}const list = this.list;if (list && list.length > 0) {this.data = list.find(datum => String(datum[this.id]) === String(this.value));}},/*** 获取参数* @returns {string|*}*/getOption() {// 根据type获取optionconst option = formatOptions[this.type];// 赋值属性Object.assign(this.$data, option);return option.serve;},/*** 获取数据*/async getData() {const serve = this.getOption();// 如果vuex中有当前类型缓存,则取缓存if (this.fieldFormats[this.type]) {this.list = this.fieldFormats[this.type];this.format();return;}if (serve instanceof Function) {// 如果serve类型为Function,则直接调用取值serve().then(res => {this.relRes(res);});} else {if (this.isDict) {await this.relDict();} else if (this.isEnum) {await this.relEnum();} else if (this.isCustom) {this.format();} else {let res;if (this.method === "post") {res = await cachePost(serve, this.params);} else {res = await cacheGet(serve, this.params);}this.relRes(res);}}},/*** 解析枚举*/async relEnum() {const res = await cacheGet(this.enumUrl, {enumType: this.serve})this.relRes(res);},/*** 解析字典*/async relDict() {const res = await cacheGet(this.dictUrl + this.serve);this.relRes(res);},/*** 解析结果*/relRes(res) {let list = this.list = res[this.dataField];this.$store.commit("fieldFormat/ADD_TYPE", {type: this.type,value: list});this.format();}},created() {this.getData();}
}
</script>

9. 创建store缓存

为了降低请求频率,降低后端请求压力,我们添加 store 进行缓存获取的数据。

创建 fieldFormat.js,内容如下:

export default {namespaced: true,state: {types: {}},mutations: {ADD_TYPE: (state, params) => {state.types[params.type] = params.value;}}
}

并添加到 store 的 modules 中:

import fieldFormat from "./modules/fieldFormat";
const store = new Vuex.Store({modules: {fieldFormat},getters: {fieldFormat: state => state.fieldFormat.types}
})export default store

10. 创建缓存请求

在表格渲染中,会创建多个相同类型的组件,由于第一次请求,缓存中没有该类型的数据,造成大量的请求,所以我们添加缓存请求,降低请求次数。

我们使用的使 axios.js,但其实普通的 ajax 也可以。

const cacheMap = {};
// 响应拦截器
service.interceptors.response.use(res => {try {// 删除缓存,这里的 api 根据个人需求变更const baseApi = res.config.url.replace(process.env.VUE_APP_BASE_API, "");let api;if (res.config.method === 'get') {api = baseApi + JSON.stringify(res.config.params);} else {api = baseApi + JSON.stringify(res.config.data);}if (cacheMap.hasOwnProperty(api)) {delete cacheMap[api];}} catch (err) {}
}/*** Get缓存请求*/
export const cacheGet = async (api, params) => {if (api.indexOf("/") !== 0) {api = "/" + api;}const key = api + JSON.stringify(params);if (!cacheMap.hasOwnProperty(key)) {cacheMap[key] = service({url: api,method: 'get',params});}return cacheMap[key];
}/*** Post缓存请求*/
export const cachePost = async (api, data) => {if (api.indexOf("/") !== 0) {api = "/" + api;}const key = api + JSON.stringify(data);if (cacheMap.hasOwnProperty(key)) {cacheMap[key] = service({url: api,method: 'post',data});}return cacheMap[key];
}

11. 添加全局组件

为了能够使组件能够全局调用,而不用单独引入,我们在 main.js 中引入,并挂载到全局

import FieldFormat from "@/components/FieldFormat";
Vue.component('FieldFormat', FieldFormat);

12. 说明

属性类可自行创建,也可以直接使用 JSON 格式,创建属性类是为了能够更方便、快捷的使用。

13. 属性

1. 类属性

属性类型说明
serveString 或 Function请求地址或请求方法或枚举类型,请求方法可以是api中的,必须是Function: () => Promise格式
idString请求后的数据列表字段,用于匹配那一条数据
labelString请求后的数据列表字段,用于自动格式化字段
methodString请求方式,默认get
dataFieldString请求后的data字段,默认data
isEnumBoolean是否枚举,开启将请求后端枚举
isDictBoolean是否字典,开启将请求后端字典
isCustomBoolean是否自定义,开启自定义数据模式
customDataObject 或 Array自定义的数据
renderFunction用于自定义渲染操作,参数为(data, list),data为当前数据项,list为全部数据列表

2. 组件属性

属性类型说明
valueString 或 Number用于匹配的值
typeString要格式化的类型
paramsObject发起请求的额外参数
alternateString没有匹配的数据时,代替显示的内容
closeTagBoolean关闭Tag标签样式
tagString要显示的Tag标签样式(默认的为default),见Element文档
tagsObject按数据显示的Tag标签样式,数据值为key,样式为值

14. 使用

1. 格式化

在需要格式化的地方,使用组件 field-format,value为已知数据值, type 为 formatOptions 中添加的名称,另外还有 params 字段用于请求自定义传参

<field-format :value="form.vehicleType" type="vehicleType"></field-format>

2. 自定义插槽

可以使用插槽实现更多场景的功能,如

<field-format :value="form.vehicleType" type="vehicleType"><template #format="{data}">{{ data.name }}</template>
</field-format>

3. 遍历

或者获取所有列表,用于遍历

<field-format type="vehicleType"><template #list="{list}"><el-select v-model="form.vehicleType"><el-optionv-for="item in list":label="item.name":value="item.vehicleTypeId":key="item.vehicleTypeId"></el-option></el-select></template></field-format>
</el-form-item>

4. 默认插槽

用以自定义追加数据

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

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

相关文章

c语言:通讯录管理系统(文件版本)

前言&#xff1a;在大多数高校内&#xff0c;都是通过设计一个通讯录管理系统来作为c语言课程设计&#xff0c;通过一个具体的系统设计将我们学习过的结构体和函数等知识糅合起来&#xff0c;可以很好的锻炼学生的编程思维&#xff0c;本文旨在为通讯录管理系统的设计提供思路和…

将nginx注册为Windows系统服务

文章目录 1、使用nssm小工具2、使用winsw小工具2.1、下载2.2、用法2.3、重命名2.4、创建配置文件2.4.1、xml文件2.4.2、config文件&#xff08;该文件可省略&#xff09; 2.5、最终文件2.6、安装与卸载 1、使用nssm小工具 该方法最简单 首先&#xff0c;下载nssm小工具&#…

HTML5+CSSDAY4综合案例一--热词

样式展示图&#xff1a; 代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>热词…

docker 基本操作

一、docker 概述 Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源。 Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机”。 Docker 的容器技术可以在一台主机上轻松为任何应用创建一个轻量级的、可移植的、自…

HomeView/主页 的实现

1. 创建数据模型 1.1 创建货币模型 CoinModel.swift import Foundation// GoinGecko API info /*URL:https://api.coingecko.com/api/v3/coins/markets?vs_currencyusd&ordermarket_cap_desc&per_page250&page1&sparklinetrue&price_change_percentage24…

机器人制作开源方案 | 齿轮传动轴偏心轮摇杆简易四足

1. 功能描述 齿轮传动轴偏心轮摇杆简易四足机器人是一种基于齿轮传动和偏心轮摇杆原理的简易四足机器人。它的设计原理通常如下&#xff1a; ① 齿轮传动&#xff1a;通过不同大小的齿轮传动&#xff0c;实现机器人四条腿的运动。通常采用轮式齿轮传动或者行星齿轮传动&#xf…

Blender:使用立方体制作动漫头像

好久没水文章 排名都掉到1w外了 ~_~ 学习一下blender&#xff0c;看能不能学习一点曲面变形的思路 一些快捷键 ctrl 空格&#xff1a;区域最大化&#xff0c;就是全屏 ctrl alt 空格&#xff1a;也是区域最大化 shift b&#xff1a;框选区域然后最大化显示该范围 shift 空…

3.springcloudalibaba gateway项目搭建

文章目录 前言一、搭建gateway项目1.1 pom配置1.2 新增配置如下 二、新增server服务2.1 pom配置2.2新增测试接口如下 三、测试验证3.1 分别启动两个服务&#xff0c;查看nacos是否注册成功3.2 测试 总结 前言 前面已经完成了springcloudalibaba项目搭建&#xff0c;接下来搭建…

AI如何帮助Salesforce从业者找工作?

在当今竞争激烈的就业市场中&#xff0c;找到满意的工作是一项艰巨的任务。成千上万的候选人竞争一个岗位&#xff0c;你需要利用一切优势从求职大军中脱颖而出。 这就是AI的用武之地&#xff0c;特别是像ChatGPT这样的人工智能工具&#xff0c;可以成为你的秘密武器。本篇文章…

【Windows】RPC调用过程实例详解

概述&#xff1a;windows 创建 RPC调用过程实例详解 参考文章&#xff1a;Remote procedure call (RPC)&#xff08;远程过程调用 (RPC)&#xff09; - Win32 apps | Microsoft Learn 文章目录 0x01、生成 UUID 和模版(IDL)文件0x02、添加 acf 文件0x03、编译 idl 文件0x04、客…

Vuex基础使用存取值+异步请求后台

目录 一、Vuex简介 1.1 定义 1.2 Vuex关键概念 1.3 使用Vuex的优势 1.4 Vuex中各个js文件的用途 1.5 Vuex各组件 1.5.1 图解 1.5.2 详解 1.6 变量传值的演变形式 二、Vuex获取值 2.1 安装 2.2 菜单栏 2.3 模块 2.4 引用 三、Vuex改变值 四、Vuex异步&请求后台…

ACK 云原生 AI 套件:云原生 AI 工程化落地最优路径

作者&#xff1a;胡玉瑜(稚柳) 前言 在过去几年中&#xff0c;人工智能技术取得了突飞猛进的发展&#xff0c;涵盖了机器学习、深度学习和神经网络等关键技术的重大突破&#xff0c;这使得人工智能在各个领域都得到广泛应用&#xff0c;对各行各业产生了深远的影响。 特别值…

cfssl自签证书

什么是cfssl&#xff1f; 即CloudFlare SSL&#xff0c;是由美国的一个叫CloudFlare的公司开发的一款开源的工具包。与OpenSSL类似&#xff0c;但是相比OpenSSL而言&#xff0c;cfssl是一个更轻量化、易于使用和理解的 PKI/TLS 解决方案&#xff0c;但是功能丰富性方面不如Ope…

计算机视觉处理的开源框架

计算机视觉是一门涉及图像和视频分析的领域&#xff0c;有许多开源的框架和库可用于构建计算机视觉应用程序。以下是一些常见的计算机视觉开源框架及其特点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合…

地级市HVV | 未授权访问合集

在网站前后端分离盛行下&#xff0c;将大部分权限控制交给前端&#xff0c;导致js中隐藏未授权或者可绕过的前端鉴权。前后端分离的好处是提高开发效率&#xff0c;同时防止黑客更直接的对服务器造成危害&#xff0c;但权限控制的工作量全部交给前端会导致大量页面未授权或者后…

Flink---12、状态后端(HashMapStateBackend/RocksDB)、如何选择正确的状态后端

星光下的赶路人star的个人主页 大鹏一日同风起&#xff0c;扶摇直上九万里 文章目录 1、状态后端&#xff08;State Backends&#xff09;1.1 状态后端的分类&#xff08;HashMapStateBackend/RocksDB&#xff09;1.2 如何选择正确的状态后端1.3 状态后端的配置 1、状态后端&am…

香港专用服务器拥有良好的国际网络连接

香港服务器在多个领域有着广泛的应用。无论是电子商务、金融交易、游戏娱乐还是社交媒体等&#xff0c;香港服务器都能够提供高效稳定的服务。对于跨境电商来说&#xff0c;搭建香港服务器可以更好地满足亚洲用户的购物需求&#xff1b;对于金融机构来说&#xff0c;香港服务器…

力扣第98题 验证二叉搜索树 c++ 与上一篇文章相似

题目 98. 验证二叉搜索树 中等 相关标签 树 深度优先搜索 二叉搜索树 二叉树 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当…

如何在小程序中设置导航栏文字颜色和背景颜色

不同商家有不同的颜色风格&#xff0c;例如有些做设计的公司&#xff0c;主要是黑色风格&#xff1b;有些卖珠宝的商家&#xff0c;主要是金色风格&#xff1b;他们的小程序&#xff0c;也需要进行同样的风格设定。下面具体介绍怎么在小程序中进行整个风格设定。 1. 在小程序管…

Gooxi国鑫搭载第四代英特尔至强可扩展处理器系列服务器焕新登场

由算力驱动的数字经济渗透到了百行千业&#xff0c;在驱动传统经济转型升级和效能优化的同时&#xff0c;也大幅度增加了各行业数据处理能力的需求 。 面对千行百业加速创新应用和AIGC时代像潮水一样奔涌算力需求&#xff0c;得益于第四代英特尔至强可扩展处理器以及基于Gooxi最…