技术栈:
vue3,html,less,antd-vue
封装代码
<template>
<div class="tabalBox">
<table :class="tabalFlex ? 'tabalFlex' : ''" id="table">
<tr class="trHead">
<th v-for="item in columns">
<a-checkbox v-if="item.key == 'select'" :checked="checkAll"
@click="getAll"></a-checkbox>
<span>
{{ item.title }}
<div v-if="item.sort">
<button @click="item.sort.top()"></button>
<button @click="item.sort.down()"></button>
</div>
</span>
</th>
</tr>
<!--
参数接受的变量
width:设置别个宽度
style:设置表格样式
select:放在columns的多选属性
-->
<tr v-for="(item, index) in dataList">
<template v-for="value in columns">
<td :width="value.width" :style="value.style">
<a-checkbox v-if="value.key == 'select'" @change="beCheck(index,
$event)" :value="item.id"
:checked="checkDataArr[index]">
</a-checkbox>
<span :title="valueKey(item, value.key)" v-if="!value.slots &&
value.key != 'id'">
{{ valueKey(item, value.key) }}
</span>
<span v-else-if="value.key == 'id'">
{{ currentPage.size * (currentPage.current - 1) + index + 1
}}
</span>
<!-- 插槽 -->
<slot v-else :name="value.slots" :value="item"></slot>
</td>
</template>
</tr>
<slot name="addNewTr"></slot>
</table>
</div>
</template>
<script lang='ts' setup>
import { ref, onMounted, watch } from "vue"
const father = defineProps<{
columns: any[],//表头参数
dataList: any[],//表格数据
currentPage?: any,//分页
delIdArr: string[],//多选删除id数组
tabalFlex?: boolean
}>()
//接受多选参数函数
const fatherFn = defineEmits(['chooseId'])
const checkDataArr = ref<boolean[]>([]);
const checkAll = ref<boolean>(false)
//在创建阶段渲染所有选中数组
onMounted(() => {
checkDataArr.value = father.dataList.map(() => false)
})
watch(
() => [father.delIdArr, father.dataList],
(newValue, oldValue) => {
if (!newValue[0][0]) {
checkDataArr.value = father.dataList.map(() => false)
checkAll.value = false
}
if (newValue[1].length != oldValue[1].length) {
checkDataArr.value = father.dataList.map(() => false)
}
},
{
deep: true
}
)
//选中某一个
const beCheck = function (num: number, e: any) {
checkDataArr.value[num] = e.target.checked
if (checkDataArr.value.indexOf(true) != -1) {
checkAll.value = true
} else {
checkAll.value = false
};
choiceDataId()
}
//选中所有
const getAll = function () {
checkAll.value = !checkAll.value
if (checkAll.value) {
checkDataArr.value = checkDataArr.value.map(() => true)
} else {
checkDataArr.value = checkDataArr.value.map(() => false)
}
choiceDataId()
}
//选中id
function choiceDataId() {
let arr: string[] = []
checkDataArr.value.forEach((item: boolean, index: number) => {
if (item) {
arr.push(father.dataList[index].id)
}
})
fatherFn('chooseId', {
value: arr,
})
}
//对value.key进行进一步解析
function valueKey(item: any, str: string): string {
// console.log("item", item);
let newStr = ""
if (str.indexOf('.') == -1) {
str == 'price' ? newStr = "¥" + item[str] : newStr = item[str]
} else {
let arr = str.split('.');
if (item[arr[0]] == null || (item[arr[0]][arr[1]] == null || undefined)) {
newStr = "数据丢失了"
} else {
newStr = item[arr[0]][arr[1]]
}
}
return newStr
}
</script>
<style scoped lang="less">
.tabalBox {
min-height: 500px;
}
.tabalFlex {
table-layout: fixed;
}
table {
width: 100%;
border-top: 1px solid rgba(46, 203, 191, 1);
tr:nth-child(1) {
background-color: #F8F8F8;
}
tr:nth-child(2n+3) {
background-color: rgba(13, 152, 162, 0.08);
}
tr {
height: 60px;
width: 100%;
th {
>span {
display: flex;
align-items: center;
justify-content: center;
>div {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-left: 5px;
button {
// width: 15px;
// height: 15px;
border: 7.5px solid transparent;
background-color: transparent;
cursor: pointer;
}
button:nth-child(1) {
border-bottom: 7.5px solid #ccc;
margin-bottom: 5px;
}
button:nth-child(2) {
border-top: 7.5px solid #ccc;
}
}
}
}
td {
text-align: center;
a {
color: #000;
cursor: auto;
}
}
}
}
</style>
页面引用使用
<tamplate>
<MyTable :columns="columns" :dataList="dataList" :delIdArr="[]" :currentPage="currentPage">
<template v-slot:avatarUrl="slotProps">
<div>
<img style="height: 20px;border-radius: 10px;" :src="slotProps.value.user.avatarUrl" alt="">
{{ slotProps.value.user.nickName }}
</div>
</template>
</MyTable>
</template>
<script setup lang="ts">
import {ref} from "vue"
import {MyTable} from "./../components/myTable.vue"
const delIdArr = ref<string[]>([])//根据需求传值,不需要多选框可直接传空数组
const dataList = ref<any[]>([])
const columns = ref<any[]>([
{
title:"全选",
key:"select"
},
{
title: "序号",
key: "id",
},
{
title: "设备编号",
key: "machineId",
slots: "machineId",
style: {
color: "rgba(15, 79, 149, 1)"
}
},
{
title: "头像/昵称",
key: "avatarUrl",
slots: "avatarUrl"
},
{
title: "手机号",
key: "user.phoneNumber",
},
{
title: "金额(元)",
key: "money",
slots: "money",
style: {
color: "rgba(255, 142, 18, 1)"
}
},
{
title: "重量Kg",
key: "weight"
},
{
title: "投递次数",
key: "userCount",
sort: {
show: true,
top: () => {
//正序
},
down: () => {
//降序
}
}
},
{
title: "积分",
key: "amount",
style: { color: 'rgba(249, 88, 88, 1)' }
},
{
title: "申请时间",
key: "createTime",
},
{
title: "开门图片",
key: "openImage",
slots: "openImage",
},
{
title: "关门图片",
key: "closeImage",
slots: "closeImage",
},
{
title: "操作",
key: "action",
slots: "action"
}
])
</script>
解析
表头:表头通过循环colums实现
表格:数据有datalist提供,并且通过colums的key值渲染数据,因为有些表格数据可能涉及插槽,传参如上。
其中解析参数时,还对基本的对象参数进行了解析,解析函数如上valueKey的function,但是多个对象嵌套的参数没法使用,比如a.b.c.d,这类需要用到递归,后期需要继续改进
总结
该组件封装下来感觉跟antd的表格组件差不多,虽说功能欠缺了很多,但是写的时候感觉很多逻辑都几乎相同,中间主要用到了父子组件传参,v-for,还有插槽等技术,需要先对这几个基础有一定的了解。