Spring Boot 整合VUE实现前端自定义字典组件
Spring Boot 整合VUE实现前端自定义字典组件
Spring Boot 整合VUE实现前端自定义字典组件
Harry技术后台管理系统,gitee地址:,采用SpringBoot2.7、MyBatis-Plus、SpringSecurity安全框架等,开发的一套权限系统,实现前后端分离前端技术栈 Vue 、Element Plus 、Vite(JS版)。
鉴于TypeScript的流行性和其在类型检查、代码智能提示等方面的优势,对前端代码进行静态类型检查,提升代码质量和可维护性。我决定出一个TypeScript版本。
后端技术栈升级计划
后端技术栈升级至Spring Boot ,这一升级将带来性能提升、新特性支持以及更好的兼容性。目前,该升级工作仍在开发中,一旦完成,我会开源出来,供大家一起学习和交流。
在网上看到Vue-Element-Admin-Thin
项目(基于 Vue + Vite5+ TypeScript5 + Element-Plus + Pinia 等主流技术栈构建的),以此作为基础,学习一下。
image-2024120202651847
在前后端分离的项目中,后端设计通常会包含一些字典值,这些字典值在前端展示时可能只是一些数字代码。为了提升用户体验,我们需要将这些数字代码转换为对应的文字描述。Vue-Element-Admin
提供了一个字典值读取及展示组件,可以方便地实现这一功能。
未使用字典
首页:我们后端先写一个获取所有字典值的一个接口/sys/dict/list
,这个接口应该返回一个包含字典编码和对应文字描述的JSO对象。返回内容格式如下:
{
"code": 200,
"message": "操作成功",
"data": [
{
"name": "用户性别",
"type": "sys_user_",
"data": [
{
"value": "0",
"label": "男",
"tagType": "success"
},
{
"value": "1",
"label": "女",
"tagType": "warning"
},
{
"value": "2",
"label": "未知",
"tagType": "info"
}
]
}
]
}
我们先看看使用字典组件的最终效果,是不是提高了可读性
使用字典组件
前端代码改写
首先在store中定义useDictStore模块,这里是用的是Pinia 存储库,在index中export
代码语言:javascript代码运行次数:0运行复制import { store } from"@/store";
import DictionaryAPI, { type DictVO, type DictData } from"@/api/system/dict";
exportct useDictStore = defineStore("dict", () => {
ct dictionary = useStorage<Record<string, DictData[]>>("dictionary", {});
ct setDictionary = (dict: DictVO) => {
dictionary.value[] = dict.data;
};
ct loadDictionaries = async () => {
// 获取所有字典值的一个接口`/sys/dict/list`
ct dictList = await DictionaryAPI.getList();
dictList.forEach(setDictionary);
};
ct getDictionary = (dictCode: string): DictData[] => {
return dictionary.value[dictCode] || [];
};
ct clearDictionaryCache = () => {
dictionary.value = {};
};
ct updateDictionaryCache = async () => {
clearDictionaryCache(); // 先清除旧缓存
await loadDictionaries(); // 重新加载最新字典数据
};
return {
dictionary,
setDictionary,
loadDictionaries,
getDictionary,
clearDictionaryCache,
updateDictionaryCache,
};
});
exportfunction useDictStoreHook() {
return useDictStore(store);
}
image-202412021111612
在components定义组件
代码语言:javascript代码运行次数:0运行复制<template>
<el-select
v-if="type === 'select'"
v-model="selectedValue"
:placeholder="placeholder"
:disabled="disabled"
clearable
:style="style"
@change="handleChange"
>
<el-option
v-for="option in opti"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
<el-radio-group
v-else-if="type === 'radio'"
v-model="selectedValue"
:disabled="disabled"
:style="style"
@change="handleChange"
>
<el-radio
v-for="option in opti"
:key="option.value"
:label="option.label"
:value="option.value"
>
{{ option.label }}
</el-radio>
</el-radio-group>
<el-checkbox-group
v-else-if="type === 'checkbox'"
v-model="selectedValue"
:disabled="disabled"
:style="style"
@change="handleChange"
>
<el-checkbox
v-for="option in opti"
:key="option.value"
:label="option.label"
:value="option.value"
>
{{ option.label }}
</el-checkbox>
</el-checkbox-group>
</template>
<script setup lang="ts">
import { useDictStore } from "@/store";
ct dictStore = useDictStore();
ct props = defineProps({
code: {
type: String,
required: true,
},
modelValue: {
type: [String, umber, Array],
required: false,
},
type: {
type: String,
default: "select",
validator: (value: string) =>
["select", "radio", "checkbox"].includes(value),
},
placeholder: {
type: String,
default: "请选择",
},
disabled: {
type: Boolean,
default: false,
},
style: {
type: Object,
default: () => {
return {
width: "00px",
};
},
},
});
ct emit = defineEmits(["update:modelValue"]);
ct opti = ref<Array<{ label: string; value: string | number }>>([]);
ct selectedValue = ref<any>(
typeof === "string" || typeof === "number"
?
: Array.isArray()
?
: undefined
);
// 监听 modelValue 变化
watch(
() => ,
(newValue) => {
if ( === "checkbox") {
selectedValue.value = Array.isArray(newValue) ? newValue : [];
} else {
selectedValue.value = newValue?.toString() || "";
}
},
{ immediate: true }
);
// 监听 opti 变化并重新匹配 selectedValue
watch(
() => opti.value,
(newOpti) => {
// opti 加载后,确保 selectedValue 可以正确匹配到 opti
if (newOpti.length > 0 && selectedValue.value !== undefined) {
ct matchedOption = newOpti.find(
(option) => option.value === selectedValue.value
);
if (!matchedOption && !== "checkbox") {
selectedValue.value = ""; // 如果不到匹配项,清空选中
}
}
}
);
// 监听 selectedValue 的变化并触发 update:modelValue
function handleChange(val: any) {
emit("update:modelValue", val);
}
// 获取字典数据
onMounted(() => {
opti.value = dictStore.getDictionary();
});
</script>
在页面中调用:
代码语言:javascript代码运行次数:0运行复制<el-form-item label="性别" prop="">
<Dict v-model="formData." code="sys_user_" />
</el-form-item>
code : 字典类型,对应接口中的
type
。根据type获取相应的字典数据
这样就加载出来了
image-2024120211450
定义DictLabel
组件
<template>
<template v-if="tagType">
<el-tag :type="tagType" :size="tagSize">{{ label }}</el-tag>
</template>
<template v-else>
<span>{{ label }}</span>
</template>
</template>
<script setup lang="ts">
import { useDictStore } from "@/store";
ct dictStore = useDictStore();
ct props = defineProps({
code: String,
modelValue: [String, umber],
size: {
type: String,
default: "default",
},
});
ct label = ref("");
ct tagType = ref<
"success" | "warning" | "info" | "primary" | "danger" | undefined
>();
ct tagSize = ref(props.size as "default" | "large" | "small");
ct getLabelAndTagByValue = async (dictCode: string, value: any) => {
// 先从本地缓存中获取字典数据
ct dictData = dictStore.getDictionary(dictCode);
// 查对应的字典项
ct dictEntry = dictData.find((item: any) => item.value == value);
return {
label: dictEntry ? dictEntry.label : "",
tag: dictEntry ? : undefined,
};
};
// 监听 props 的变化,获取并更新 label 和 tag
ct fetchLabelAndTag = async () => {
ct result = await getLabelAndTagByValue(
as string,
);
label.value = result.label;
tagType.value = as
| "success"
| "warning"
| "info"
| "primary"
| "danger"
| undefined;
};
// 首次挂载时获取字典数据
onMounted(fetchLabelAndTag);
// 当 modelValue 发生变化时重新获取
watch(() => , fetchLabelAndTag);
</script>
在页面中调用:
代码语言:javascript代码运行次数:0运行复制<el-table-column label="性别" width="100" align="center" prop="">
<template #default="scope">
<DictLabel
v-model="scope.row."
code="sys_user_"
size="small"
/>
</template>
</el-table-column>
显示效果:
注意 需要在路由跳转前加载字典数据,否则会出现字典数据未加载完成导致页面渲染异常
所以,我们在登录之后获取用户信息时,同时加载字典数据
到这里,字典值读取及展示组件就介绍完了。更多文章推荐,搜“Harry技术”,关注我,带你看不一样的人间烟火!
本文参与 腾讯云自媒体同步曝光计划,分享自。原始发表:2024-12-0,如有侵权请联系 cloudcommunity@tencent 删除接口前端数据sprinue#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
推荐阅读
留言与评论(共有 7 条评论) |
本站网友 怎样治疗早泄 | 14分钟前 发表 |
disabled="disabled" | |
本站网友 食醋减肥 | 16分钟前 发表 |
key="option.value" | |
本站网友 莲花跑车 | 27分钟前 发表 |
一旦完成 | |
本站网友 小针刀 | 30分钟前 发表 |
placeholder="placeholder" | |
本站网友 柿饼不能和什么一起吃 | 3分钟前 发表 |
label="option.label" | |
本站网友 桂林房产网 | 8分钟前 发表 |
{ type |