在使用element-plus的虚拟表格化组件el-table-v2渲染数据和组件的方法时,由于官网的使用示例中只有ts或tsx版,文章则是使用js和jsx的示例及一些虚拟化表格组件的注意事项。
columns属性中自定义单元格渲染器的字段是cellRenderer,类型为VueComponent/(props: CellRenderProps) => VNode
这里我使用element-plus的按钮组件ElButton和标签组件ElTag做示例,方法有两种(推荐第一种):
import { ref, h } from "vue";
import { ElMessageBox, ElMessage, ElButton ,ElTag} from "element-plus";
//columns 是一个数组,里面的值为每一列的配置信息
const columns = [
{
key: "release_status",
dataKey: "release_status",
title: "发放状态",
width: 80,
cellRenderer: ({ cellData }) =>
h(
ElTag,//这里不能写成字符串'ElTag',如果是普通的html标签如'div',则可以。
{ type: cellData == "可发放" ? "success" : "danger" },
{ default: () => cellData }//也可以写成字符串如'这是标签内容',但控制台会有警告
)
}
]
import { ref, h, resolveComponent } from "vue";
const ElButton = resolveComponent("ElButton");
const ElTag = resolveComponent("ElTag");
//cellRenderer函数代码同上
完整代码如下:
<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 ElButton = resolveComponent("ElButton");
// const ElTag = resolveComponent("ElTag");
const tableData = ref([]);
//获取表格数据(mockjs生成)的方法
const getApiData = () => {
request("table2").then((res) => {
tableData.value = res.data;
});
};
getApiData();
//columns 是一个数组,里面的值为每一列的配置信息
const columns = [
{
key: "id",
dataKey: "id",//需要渲染当前列的数据字段,如{id:9527,name:'Mike'},则填id
title: "id",//显示在单元格表头的文本
width: 80,//当前列的宽度,必须设置
fixed: true,//是否固定列
},
{
key: "name",
dataKey: "name",//需要渲染当前列的数据字段,如{id:9527,name:'Mike'},则填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>
由于vite搭建的项目默认不支持jsx,需要先安装@vitejs/plugin-vue-jsx插件并在vite.config.js中配置:
//yarn
yarn add @vitejs/plugin-vue-jsx -D
//npm
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", //需要渲染当前列的数据字段,如{id:9527,name:'Mike'},则填id
title: "id", //显示在单元格表头的文本
width: 80, //当前列的宽度,必须设置
fixed: true, //是否固定列
},
{
key: "name",
dataKey: "name", //需要渲染当前列的数据字段,如{id:9527,name:'Mike'},则填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>
补充增加输入框示例:
import { ref } from "vue";
import { ElInput } from "element-plus";
let tableData=ref();//表格数据
const columns = [
{
key: "dengji",
dataKey: "dengji",
title: "等级",
width: 120,
cellRenderer: (data) =>
h(ElInput, {
modelValue: data.cellData,
clearable:true,
placeholder:"请输入",
onInput: (e) => onChange(e, data),
}),
},
];
const onChange = (e, data) => {
//e为当前输入框的值,data为需要传递的参数
console.log(e, data);
//修改当前项输入框的值
tableData.value.forEach((item) => {
if (item.id == data.rowData.id) {
item.dengji = e;
}
});
};
注意:
实测时,当对表格行数据hover时、blur时、输入框操作时,均会执行onInput方法,而且是多次,比如表格可视区域的行数是10行,那么就执行10次,即便只是操作单行数据,也会执行10次。
element-plus版本升级至2.4.4无此问题,只在当前项的输入框值变化时执行
个人建议,如果要用此虚拟表格组件的话,只做纯数据展示即可,不加任何数据操作;如果涉及要在表格中对数据操作,还是使用基于vue的插件vxe-table。