【vue】vue3-字典组件

思路

  • 考虑性能问题,转换字典数据为对象 KV 的格式,简化循环次数。
  • 将传入的 value 转成数组,并且考虑字符串逗号分割情况(支持多 value 转换 label)。
  • 循环 valueList 数组,根据数组项找到对应的字典数据。
  • 根据字典数据的 elTagType 或 elTagClass 来渲染不同的样式。
  • 纯文本显示时,需要使用什么分隔符来分隔。
  • 考虑未找到匹配的数据时是否显示 value。

实现

RocDictTag.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<template>
<div class="roc-dict-tag">
<template v-for="(v, i) in valueList" :key="v">
<template v-if="optionsObj[v]">
<!-- tag 标签 -->
<template v-if="optionsObj[v].elTagType">
<el-tag :type="optionsObj[v].elTagType">{{ optionsObj[v].label }}</el-tag>
</template>
<!-- 文字颜色样式 -->
<template v-else-if="optionsObj[v].elTagClass">
<span :class="[optionsObj[v].elTagClass]">{{ optionsObj[v].label }}</span>
<span v-if="i < valueList.length - 1">{{ dot }}</span>
</template>
<!-- 普通文字 -->
<template v-else>
<span>{{ optionsObj[v].label }}</span>
<span v-if="i < valueList.length - 1">{{ dot }}</span>
</template>
</template>
<template v-else>
<span v-if="showValue">{{ v }}</span>
</template>
</template>
</div>
</template>

<script setup>
import { computed } from "vue";

const props = defineProps({
// 数据
options: {
type: Array,
required: true,
},
// 当前的值
value: {
type: [Number, String, Array],
required: true,
},
// 当未找到匹配的数据时是否显示value
showValue: {
type: Boolean,
default: true,
},
// 使用分隔符 默认“、”
dot: {
type: String,
default: "、",
},
});

const optionsObj = computed(() => {
const obj = {};
props.options.forEach((item) => {
obj[item.value] = item;
});
return obj;
});

const valueList = computed(() => {
let list;
if (!Array.isArray(props.value)) {
if (typeof props.value === "string" && props.value.indexOf(",") !== -1) {
list = props.value.split(",");
} else {
list = [props.value];
}
} else {
list = props.value;
}
return list;
});
</script>

<style scoped>
.el-tag + .el-tag {
margin-left: 10px;
}
.primary {
color: #409eff;
}
.success {
color: #67c23a;
}
.info {
color: #909399;
}
.warning {
color: #e6a23c;
}
.danger {
color: #f56c6c;
}
</style>

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<template>
<RocDictTag :options="dict" :value="[1, 2]" dot="、"></RocDictTag>
</template>

<script setup>
import RocDictTag from "@/components/RocDictTag/RocDictTag.vue";

/**
* 字典
* @typedef Dict
* @property {string} label
* @property {string | Number} value
* @property {'' | 'primary' | 'success' | 'info' | 'warning' | 'danger'} elTagType
* @property {'' | 'primary' | 'success' | 'info' | 'warning' | 'danger'} elTagClass
*/

/**
* @type {Dict[]}
*/
const dict = [
{
label: "男",
value: 1,
elTagType: "",
elTagClass: "",
},
{
label: "女",
value: 2,
elTagType: "",
elTagClass: "",
},
];
</script>