Element-plus 虚拟表格 绑定单元行的双击事件、单击事件 (Vue3、Nuxt3)
由于做的内容需要渲染大量数据,用原本的表格渲染会十分卡顿,所以选择使用虚拟化表格,官方文档:Virtualized Table 虚拟化表格 | Element Plus (element-plus.org)但是由于这个表格还是beta版,所以提供的事件也非常少。我做的项目需要实现表格的单击、双击单元行,来进行操作这一行的数据,但是翻阅文档并没有找到这个事件,那么只能自己实现了。想获取点击/双击的
更新:
其实是有提供的,只是官网文档给的描述太隐蔽了,我没看出来是啥意思。。。
element-plus 虚拟化表格如何自定义事件_会做饭的二哈的博客-CSDN博客
传入一个对象,里面的属性是原生DOM事件,比如onClick等
下面的可以不用看了,是一些DOM操作,因为我不知道官方提供了这些。。。
———————————————————————————————————————————
一、引言
由于做的内容需要渲染大量数据,用原本的表格渲染会十分卡顿,所以选择使用虚拟化表格,官方文档:Virtualized Table 虚拟化表格 | Element Plus (element-plus.org)
但是由于这个表格还是beta版,所以提供的事件也非常少,如下:
我做的项目需要实现表格的单击、双击单元行,来进行操作这一行的数据,但是翻阅文档并没有找到这个事件,那么只能自己实现了。
二、代码
话不多说,直接上代码 (基于Nuxt3,比普通的Vue3多嵌套了一层client-only组件,删掉就行。除此之外,Nuxt3会自动帮忙引入vue中的函数,所以vue3的小伙伴需要你自己去引入一些组件和函数)
下面的代码实现了,双击获取当前单元行在数组中的索引,并根据索引获取该单元行的数据
所用技术:nuxt3 / vue3 、 Element-plus 、tsx / jsx、原生js事件
<template>
<div class="test">
<client-only>
<el-table-v2 :columns="columns" :data="list" :width="1300" :row-class="rowClassName" :height="300"
@dblclick="dblclick" />
</client-only>
</div>
</template>
<script setup lang='tsx'>
import { ElDropdown, ElDropdownMenu, ElDropdownItem, } from 'element-plus'
import type { Column } from 'element-plus'
/**双击事件 */
const dblclick = (e: any) => {
/**当前点击的元素 */
const target = e.target
/**当前点击的元素的父元素,需要不断向上寻找,找到class为 el-table-v2__row 的元素,说明找到真正的"行"了 */
let row = target.parentNode
// console.log(row, row.className);
//不断循环向上查找父元素,直到找到 “行” : el-table-v2__row
while (1) {
/**把类名切割,防止多类名影响。 */
const nowClassArr = row.className?.split(' ') || []
//如果这个row的类名包含el-table-v2__row,就是我们要找的行了
if (nowClassArr.indexOf('el-table-v2__row') > -1) break
//如果发现了其它的的类名,说明点错位置了 (TODO:这里用到了多次indexof,感觉很浪费,可能有优化方法)
if (nowClassArr.indexOf('el-table-v2__header') > -1 || nowClassArr.indexOf('el-virtual-scrollbar') > -1 || nowClassArr.indexOf('el-table-v2__empty') > -1) {
console.log('点击的可能是表头、滚动条、空列表,不做操作');
return
}
//下面是没有找到正确元素,会不断向上查找父元素
const parentNode = row.parentNode //获取父元素
if (!parentNode) {//如果为空了就返回,避免死循环
console.log('没有找到');
return
}
row = parentNode
}
// console.log(row); //最终这里拿到的就是行元素了
/**父元素的class为_index的子元素 */
const indexSpan = row.querySelector('._index')
if (!indexSpan) {//这个为空 说明失败了
console.log('获取失败,拿到的行为', row);
return
}
/**当前单元行在数组中的序号 */
const index = parseInt(indexSpan!.innerHTML)
if (isNaN(index)) {
console.log('获取失败,根据dom查看原因:', row, indexSpan);
return
}
console.log('拿到当前单元行在列表中的索引值', index);
console.log('根据索引,拿到当前单元行的数据', list[index]);
}
/**随便设置一个点击事件 */
const handle = (id: number) => {
console.log('点击了这个按钮,id为', id);
}
/**给某个单元行特殊类名 这里主要的用处是给每个数据加索引值,方便我们后面获取 */
const rowClassName = ({ rowData, rowIndex }: { rowData: any, rowIndex: number }) => {
// if (rowData?.id == 'xxxx') {//如果你想让某个单元行有特殊样式,就可以这么做。参考: http://element-plus.org/zh-CN/component/table-v2.html#带状态的表格
// return `xxxxx`
// }
rowData._index = rowIndex //给每一个数据加一个序号,方便我们到时候获取
return ``
}
/**表头数据 */
const columns: Column<any>[] = reactive([
{
key: 'name',
title: '姓名',
dataKey: 'name',
width: 500,
},
{
key: 'age',
title: '年龄',
dataKey: 'age',
width: 500,
},
{
key: 'id',
title: '',
dataKey: 'id',
width: 500,
cellRenderer: () => <ElDropdown v-slots={{
dropdown: ({ cellData: id }: { cellData: number }) => <ElDropdownMenu>
<ElDropdownItem onClick={() => handle(id)}>
操作1
</ElDropdownItem>
<ElDropdownItem disabled>待添加</ElDropdownItem>
</ElDropdownMenu>
}}>
<span style={{ cursor: "pointer" }}>...</span>
</ElDropdown>
},
{
key: '_index',//这里的_index不是list数据中自带的,而是在 rowClassName 函数中顺便加上的
title: '',
dataKey: '_index',
width: 0, //这里选择让索引值不显示,你可以根据你的需要设置
align: 'center',
cellRenderer: ({ cellData: _index }) => <span style={{ display: 'none' }} class='_index'>{_index}</span>//这里选择让索引值不显示,你可以根据你的需要设置
},
])
/**测试数据 */
const list: any[] = [
{
name: '测试1',
age: 18,
id: 1,
},
{
name: '测试2',
age: 20,
id: 2,
},
{
name: '测试3',
age: 15,
id: 3,
},
]
</script>
<style lang='less' scoped>
.test {
color: black;
background-color: white;
}
</style>
三、原理
1. 关于 jsx / tsx 可以去了解相关文档,这里用的挺多,也可以看上一篇文章 在Vue3中使用 tsx / jsx + 插槽 (element-plus中的tsx写法与插槽)_l煎饼果子的博客-CSDN博客
2. 想获取点击/双击的单元行的数据,那么我们可以通过获取这个单元行的索引,进而获取数据。那么怎么获得索引呢?我这边是通过 给列表中每一项都添加一个_index 数据,用于存放索引,并且在页面中用dom渲染出索引。然后根据双击/点击事件的事件对象e,获取点击的元素,然后不断向上寻找父元素,直到找到当前的单元行的dom元素。然后获取当前单元行的存放索引的元素,根据innerHTML提取出索引。 (这里为了页面美观,把索引display: none;了,你可以根据需要显示)
四、结语
本代码有很多缺点,但是也基本实现了需求。如果大家有更好的方法请告诉我,我也很需要
下面讲一下存在的缺点,首先是多次使用了 indexOf 函数,可能存在性能问题 + 不美观,同时我做的错误判断没有包括所有情况,如果大家在使用过程中发现了bug,需要进行排除
这种获取dom对象的做法,肯定是不如组件直接对外暴露一个方法的,但是我也没办法了,希望element官方在未来能暴露出表格行的双击/单击事件吧
tip: 除此之外,还可以在每一个columns单元格的渲染函数中,给元素直接绑定事件。但是缺点就是,有几个表头,就要绑定几次事件,可能还会影响其它元素的事件。
更多推荐
所有评论(0)