前言
由于开发中频繁使用到下拉表格组件,每次重新写太浪费时间了,所以将其封装为一个通用组件便于日后重复利用。
组件实时详情可查看gitee
用法
属性(带有[Required]为必填属性) | 说明 |
---|---|
data[Required] | 双向绑定数据 |
fields[Required] | 表格列对象 |
tableData[Required] | 表格数据对象 |
value | 双向绑定数据的值(为空时data属性为表格当前行数据对象) |
label | 选择框显示的文本内容(为空时分别查看value和objKey是否为空,若value和objKey都有值,则value优先级大于objKey) |
objKey | 对象key(绑定值的唯一标识,绑定值为对象时必填) |
placeholder | 选择框占位文本 |
size | 组件大小 |
border | 表格是否带有边 |
示例代码及效果展示
<template>
<div>
<SelectTable
v-model:data="data"
:fields="fields"
:tableData="tableData"
:label="label"
:objKey="objKey"
:border="true"
></SelectTable>
<el-button @click="test">测试</el-button>
</div>
</template>
<script setup lang="ts">
import SelectTable from "./components/SelectTable.vue";
import { ref } from "vue";
const data = ref({
id: "1002",
name: "李四",
address: "No. 189, Grove St, Los Angeles",
});
const objKey = ref("id");
const label = ref("name");
const test = () => {
console.log(data.value);
};
const fields = [
{
prop: "id",
label: "ID",
width: 180,
},
{
prop: "name",
label: "姓名",
width: 180,
},
{
prop: "address",
label: "地址",
width: 200,
showTooltip: true,
},
];
const tableData = [
{
id: "1001",
name: "张三",
address: "No. 189, Grove St, Los Angeles",
},
{
id: "1002",
name: "李四",
address: "No. 189, Grove St, Los Angeles",
},
{
id: "1003",
name: "王五",
address: "No. 189, Grove St, Los Angeles",
},
{
id: "1004",
name: "赵六",
address: "No. 189, Grove St, Los Angeles",
},
];
</script>
<style scoped></style>
效果
QQ录屏20231115092710
源代码
<!--
* SelectTable 下拉表格组件
* @author: Goal
* @since: 2023-11-13
* SelectTable.vue
*
* 属性(带有[Required]为必填属性)
* data[Required]: 双向绑定数据
* fields[Required]: 表格列对象
* tableData[Required]: 表格数据对象
* value: 双向绑定数据的值(为空时data属性为表格当前行数据对象)
* label: 选择框显示的文本内容(为空时分别查看value和objKey是否为空,若value和objKey都有值,则value优先级大于objKey)
* objKey: 对象key(绑定值的唯一标识,绑定值为对象时必填)
* placeholder: 选择框占位文本
* size: 组件大小
* border: 表格是否带有边框
-->
<template>
<div>
<el-select
ref="selectTable"
v-model="state.selectShowValue"
:placeholder="props.placeholder"
:size="props.size"
>
<template #empty>
<el-table
:data="props.tableData"
:highlight-current-row="props.isHighlight"
style="width: 100%"
:size="props.size"
:border="props.border"
@current-change="handleCurrentChange"
>
<el-table-column
v-for="field in props.fields"
:prop="field.prop"
:label="field.label"
:width="field.width"
:show-overflow-tooltip="field.showTooltip"
/>
</el-table>
</template>
</el-select>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, onMounted } from "vue";
interface Field {
prop: string;
label: string;
width: number;
showTooltip?: boolean;
}
interface Props {
data: any;
fields: Field[];
tableData: object[];
label?: string;
value?: string;
objKey?: string;
isHighlight?: boolean;
size?: string;
placeholder?: string;
border?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
placeholder: "请选择",
size: "default",
isHighlight: true,
value: undefined,
label: undefined,
border: false,
});
interface Emits {
(e: "update:data", val: any): void;
}
const emits = defineEmits<Emits>();
onMounted(() => {
//处理数据回显
// debugger;
if (props.data !== null) {
// 配置label则显示label
if (typeof props.label !== "undefined") {
// 配置了value属性,则找到与value属性值一样的表格行对象,将配置的label回显到下拉框
if (typeof props.value !== "undefined") {
let row = props.tableData.find(
(item) => item[props.value] === props.data
);
state.selectShowValue =
typeof row === "undefined" ? props.data : row[props.label];
// 配置了objKey属性,则找到与objKey属性值一样的表格行对象,将配置的label回显到下拉框
} else if (typeof props.objKey !== "undefined") {
let row = props.tableData.find(
(item) => item[props.objKey] === props.data[props.objKey]
);
state.selectShowValue =
typeof row === "undefined"
? props.data[props.objKey]
: row[props.label];
}
//没有配置label属性则回显value或者objKey
} else {
// 配置了value属性,则找到与value属性值一样的表格行对象,将配置的label回显到下拉框
if (typeof props.value !== "undefined") {
let row = props.tableData.find(
(item) => item[props.value] === props.data
);
state.selectShowValue =
typeof row === "undefined" ? props.data : row[props.value];
// 配置了objKey属性,则找到与objKey属性值一样的表格行对象,将配置的label回显到下拉框
} else if (typeof props.objKey !== "undefined") {
let row = props.tableData.find(
(item) => item[props.objKey] === props.data
);
state.selectShowValue =
typeof row === "undefined" ? props.data : row[props.objKey];
}
}
}
});
const selectTable = ref();
const state = reactive({
selectValue: null,
selectShowValue: null,
});
/**
* 点击当前行事件
* @param val
*/
const handleCurrentChange = (val: any) => {
// 如果没有配置label则显示value或者objKey
setLabel(val);
// 设置双向绑定值
if (typeof props.value !== "undefined") {
emits("update:data", val[props.value]);
} else {
emits("update:data", val);
}
selectTable.value.blur();
};
const setLabel = (val: any) => {
// 如果没有配置label则显示value或者objKey
if (typeof props.label === "undefined") {
// 如果配置了value,则显示value
if (typeof props.value !== "undefined") {
state.selectShowValue = val[props.value];
} else if (typeof props.objKey !== "undefined") {
//没有配置value但配置了objKey,则显示objKey
state.selectShowValue = val[props.objKey];
}
} else {
state.selectShowValue = val[props.label];
}
};
</script>
<style scoped></style>
总结
这是第一个做前端的通用组件封装,肯定有很多不到位的地方。后续可能还会加上多选的功能,希望各位前端大佬能在评论区指出我问题所在并且提出宝贵的意见🙏🙏。