今天在学习使用element-plus的虚拟化表格时,遇到了一个问题,就是需要在表格项中自定义渲染内容(比如渲染一个Tag标签,渲染一个下拉框组件等) 可见官网示例:Virtualized Table 虚拟化表格 | Element Plus (element-plus.org)
关于jsx / tsx 可以自行搜索相关文档去学习,我是因为之前学习过react所以了解。
但是官方给的示例中,只示例了一些普通的组件的使用,并没有告诉如何使用插槽(原本在vue的template中写,是直接写template插槽即可,但是在tsx中不能这么写)。经过多方查找,终于找到了方法,就是在组件标签中有个v-slots属性,给里面传入一个对象,键是插槽名,值是render函数。
比如element-plus中的Popover组件,就有两个插槽,一个是默认插槽,一个是具名插槽。要想在tsx中使用,需要这样:
下面这个是在vue的template标签中的写法。
<template> <el-popover :width="300" > <template #reference> 这里是普通内容 </template> <template #default> 这里是悬浮之后,弹出的提示框的内容 </template> </el-popover> </template>
复制
但是在tsx中,不能这样写,会报错。我们需要这样:
<script lang="tsx" setup> import { Column, ElPopover } from 'element-plus'; const columns: Column<any>[] = [ { key: 'id', title: '', dataKey: 'id', width: 40, align: 'center', cellRenderer: ({ cellData: id }) => ( <ElPopover width={300} v-slots={{ reference: () => <div>这里是普通内容</div>, default: () => <div>这里是悬浮之后,弹出的提示框的内容</div> }}> </ElPopover> ) } ] </script>
复制
解释 及 tsx的注意事项:
1. 首先注意script标签的 lang 写的是 tsx 或 jsx,才能在里面写tsx代码。
2. 和vue不一样的是,在jsx / tsx中,想使用变量是单花括号 { xxx } (vue是双花括号 {{ }} 或者属性前加上冒号)。所以在v-slots属性中,虽然用了双括号,但是实际上传递的其实是一个对象,里面写的东西要遵循对象的写法(键值对)。v-slots中:键是插槽名,值是render函数
3. 组件名不能用 el-popover 的写法,需要使用双驼峰命名法 ElPopover
4. tsx中给事件绑定函数,使用 onXxxx = { } 的写法,比如onClick={ },括号里面写函数的名字(不是字符串)。如果想传递参数,则这样写 onClick={ () => xxx(id) }。传递一个高阶的箭头函数。
下面给出我用element-plus的虚拟化表格的代码示例 (基于Nuxt3,所以额外嵌套了一个client-only标签)
<template> <div class="list"> <client-only> <el-table-v2 :columns="columns" :data="list" :width="1300" :height="600"/> </client-only> </div> </template> <script lang="tsx" setup> import { ElDropdown, ElDropdownMenu, ElTag, ElTooltip, ElDropdownItem, } from 'element-plus' import { Loading as LoadingIcon } from '@element-plus/icons-vue' import type { Column } from 'element-plus' /**表头数据 */ const columns: Column<any>[] = [ { key: '_name', title: '歌名', dataKey: '_name', width: 500, }, { key: '_artists', title: '歌手', dataKey: '_artists', width: 275, }, { key: '_album', title: '专辑', dataKey: '_album', width: 275, }, { key: 'fee', title: '标签', dataKey: 'fee', width: 100, align: 'center', cellRenderer: ({ cellData: fee }) => ( <ElTooltip content={fee === 0 ? '免费' : fee === 1 ? 'VIP' : fee === 4 ? '专辑' : '可听'}> { fee === 0 ? <ElTag type="success">免费</ElTag> : fee === 1 ? <ElTag type="warning">VIP</ElTag> : fee === 4 ? <ElTag type="info">专辑</ElTag> : <ElTag type="success">可听</ElTag> } </ElTooltip> ), }, { key: '_time', title: '时长', dataKey: '_time', width: 70, }, { key: 'id', title: '', dataKey: 'id', width: 40, cellRenderer: () => <ElDropdown v-slots={{ dropdown: ({ cellData: id }: { cellData: number }) => <ElDropdownMenu> <ElDropdownItem onClick={() => del(id)}> 删除 </ElDropdownItem> <ElDropdownItem disabled>待添加</ElDropdownItem> </ElDropdownMenu> }}> <span style={{ color: 'var(--center-color)' }}>...</span> </ElDropdown> }, ] const del = (id: number)=>{ } /** 测试列表 */ const list: Array<tableData> = [ { _name: '歌曲名', _album: '专辑名', _artists: '歌手名', _time: '时长' id: 0, fee: 0 } ] </script>
复制