在使用element-plus的虚拟表格化组件el-table-v2渲染数据和组件的方法时,由于官网的使用示例中只有ts或tsx版,文章则是使用js和jsx的示例及一些虚拟化表格组件的注意事项。
注意事项:
在设置columns属性时,其中的宽度字段(width)必须设置值(只能是数字类型)且每一列都要设置,不然会出现数据不显示或是只显示一列的情况。 先看效果图(数据是mockjs随机生成的)
columns属性中自定义单元格渲染器的字段是cellRenderer,类型为VueComponent/(props: CellRenderProps) => VNode
一、js方式,主要使用函数 h() 用于创建 vnodes
这里我使用element-plus的按钮组件ElButton和标签组件ElTag做示例,方法有两种(推荐第一种):
- 直接从UI框架中引入,然后在h函数的第一个参数中传入组件,需要注意的是,如果第一个参数直接传入字符串如’ElTag’,是渲染无效的,普通的html标签是可以的,第三个参数如果传入的数据是字符串文本,控制台会有警告信息,提示换为函数形式更佳,示例:
import { ref, h } from "vue";
import { ElMessageBox, ElMessage, ElButton ,ElTag} from "element-plus";
const columns = [
{
key: "release_status",
dataKey: "release_status",
title: "发放状态",
width: 80,
cellRenderer: ({ cellData }) =>
h(
ElTag,
{ type: cellData == "可发放" ? "success" : "danger" },
{ default: () => cellData }
)
}
]
- 使用vue的 resolveComponent(按名称手动解析已注册的组件),需要element-plus全局引入
import { ref, h, resolveComponent } from "vue";
const ElButton = resolveComponent("ElButton");
const ElTag = resolveComponent("ElTag");
完整代码如下:
<template>
<div class="">
<div class="title">虚拟化表格示例</div>
<el-divider></el-divider>
<div style="width: 100%; height: 500px">
<el-auto-resizer>
<template #default="{ height, width }">
<el-table-v2
:columns="columns"
:data="tableData"
:width="width"
:height="height"
:row-class="tableRowClassName"
fixed
/>
</template>
</el-auto-resizer>
</div>
<div style="margin-top: 10px">
共
<el-link type="primary" style="font-size: 20px">{{
tableData.length
}}</el-link>
条数据
</div>
</div>
</template>
<script setup>
import { ref, h, resolveComponent } from "vue";
import { ElMessageBox, ElMessage,ElButton,ElTag} from "element-plus";
import { request } from "../../api/request";
const tableData = ref([]);
const getApiData = () => {
request("table2").then((res) => {
tableData.value = res.data;
});
};
getApiData();
const columns = [
{
key: "id",
dataKey: "id",
title: "id",
width: 80,
fixed: true,
},
{
key: "name",
dataKey: "name",
title: "姓名",
width: 100,
fixed: true,
},
{
key: "id_number",
dataKey: "id_number",
title: "证件号码",
width: 180,
},
{
key: "department",
dataKey: "department",
title: "部门",
minWidth: 100,
width: 110,
},
{
key: "position",
dataKey: "position",
title: "职位",
width: 140,
},
{
key: "grade",
dataKey: "grade",
title: "等级",
width: 120,
},
{
key: "release_status",
dataKey: "release_status",
title: "发放状态",
width: 80,
cellRenderer: ({ cellData }) =>
h(
ElTag,
{ type: cellData == "可发放" ? "success" : "danger" },
{ default: () => cellData }
),
},
{
key: "handle",
title: "操作",
width: 100,
align: "center",
cellRenderer: (data) =>
h(
ElButton,
{ onClick: () => handleDelete(data), type: "danger", icon: "Delete" },
{ default: () => "删除" }
),
},
];
const tableRowClassName = ({ row, rowIndex }) => {
let step = 4;
for (let i in tableData.value) {
if (rowIndex === step * i - 3) {
return "warning-row";
}
if (rowIndex === step * i - 1) {
return "success-row";
}
}
return "";
};
const handleDelete = (data) => {
ElMessageBox.confirm(`确定删除 ${data.rowData.name}?`, "提 示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
tableData.value.splice(data.rowIndex, 1);
ElMessage({
type: "success",
message: "删除成功",
});
})
.catch(() => {
ElMessage({
type: "info",
message: "取消删除",
});
});
};
</script>
二、 jsx方式
由于vite搭建的项目默认不支持jsx,需要先安装@vitejs/plugin-vue-jsx插件并在vite.config.js中配置:
yarn add @vitejs/plugin-vue-jsx -D
npm install @vitejs/plugin-vue-jsx -D
vite.config.js配置
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from '@vitejs/plugin-vue-jsx';
export default defineConfig({
plugins: [vue(),vueJsx()]
})
使用jsx的方式就比较简捷了,需要在script标签设置lang属性等于jsx,在cellRenderer函数中可以直接使用jsx的语法和UI组件(还有自定义组件),完整代码示例如下:
<template>
<div class="">
<div class="title">虚拟化表格示例</div>
<el-divider></el-divider>
<div style="width: 100%; height: 500px">
<el-auto-resizer>
<template #default="{ height, width }">
<el-table-v2
:columns="columns"
:data="tableData"
:width="width"
:height="height"
:row-class="tableRowClassName"
fixed
/>
</template>
</el-auto-resizer>
</div>
<div style="margin-top: 10px">
共
<el-link type="primary" style="font-size: 20px">{{
tableData.length
}}</el-link>
条数据
</div>
</div>
</template>
<script lang="jsx" setup>
import { ref } from "vue";
import { ElMessageBox, ElMessage } from "element-plus";
import { request } from "../../api/request";
const tableData = ref([]);
const getApiData = () => {
request("table2").then((res) => {
tableData.value = res.data;
});
};
getApiData();
const columns = [
{
key: "id",
dataKey: "id",
title: "id",
width: 80,
fixed: true,
},
{
key: "name",
dataKey: "name",
title: "姓名",
width: 100,
fixed: true,
},
{
key: "id_number",
dataKey: "id_number",
title: "证件号码",
width: 180,
},
{
key: "department",
dataKey: "department",
title: "部门",
minWidth: 100,
width: 110,
},
{
key: "position",
dataKey: "position",
title: "职位",
width: 140,
},
{
key: "grade",
dataKey: "grade",
title: "等级",
width: 120,
},
{
key: "release_status",
dataKey: "release_status",
title: "发放状态",
width: 80,
cellRenderer: ({ cellData }) => (
<el-tag type={cellData == "可发放" ? "success" : "danger"}>
{cellData}
</el-tag>
),
},
{
key: "handle",
title: "操作",
width: 100,
align: "center",
cellRenderer: (data) => (
<>
<el-button
type="danger"
icon="Delete"
onClick={handleDelete.bind(this, data)}
>
删除
</el-button>
</>
),
},
];
const tableRowClassName = ({ row, rowIndex }) => {
let step = 4;
for (let i in tableData.value) {
if (rowIndex === step * i - 3) {
return "warning-row";
}
if (rowIndex === step * i - 1) {
return "success-row";
}
}
return "";
};
const handleDelete = (data) => {
ElMessageBox.confirm(`确定删除 ${data.rowData.name}?`, "提 示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
tableData.value.splice(data.rowIndex, 1);
ElMessage({
type: "success",
message: "删除成功",
});
})
.catch(() => {
ElMessage({
type: "info",
message: "取消删除",
});
});
};
</script>
|