Element-plus virtual table binds double-click events and click events of unit rows (Vue3, Nuxt3)

renew:

In fact, it is provided, but the description given in the official website document is too cryptic, and I didn't understand what it meant. . .

How to customize events for element-plus virtualized tables_Erha's Blog-CSDN Blog

 Pass in an object whose attributes are native DOM events, such as onClick, etc.

You don’t need to read the following, they are some DOM operations, because I don’t know that they are officially provided. . .

———————————————————————————————————————————

I. Introduction

        Since the content required to render a large amount of data, rendering with the original table would be very laggy, so I chose to use a virtualized table. Official document: Virtualized Table | Element Plus (element-plus.org)

        However, since this form is still in beta version, there are very few events provided, as follows:

         The project I am working on needs to implement single-click and double-click cell rows in the table to operate the data in this row. However, I did not find this event when looking through the document, so I had to implement it myself.

2. Code

        Without further ado, let’s go directly to the code (based on Nuxt3, which has one more layer of client-only components nested than ordinary Vue3, just delete it. In addition, Nuxt3 will automatically help introduce functions in vue, so vue3 is small Partners need you to introduce some components and functions yourself)

        The following code is implemented. Double-click to obtain the index of the current cell row in the array, and obtain the data of the cell row based on the index.

        Technologies used: nuxt3/vue3, Element-plus, tsx/jsx, native js events

<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>

3. Principle

1. Regarding jsx/tsx , you can learn about relevant documents. There are many used here. You can also read the previous article on  using tsx/jsx + slot in Vue3 (tsx writing method and slot in element-plus)_l pancake fruit Blog-CSDN Blog

2. If we want to get the data of the clicked/double-clicked unit row, we can get the data by getting the index of the unit row . So how to get the index? What I do here is add an _index data to each item in the list to store the index, and use DOM to render the index in the page . Then, according to the event object e of the double-click/click event, the clicked element is obtained, and then the parent element is searched upward until the dom element of the current unit row is found. Then get the element that stores the index of the current unit row, and extract the index based on innerHTML . (For the sake of page beauty, the index is displayed: none; here, you can display it as needed)

4. Conclusion

        This code has many shortcomings, but it basically meets the requirements. If you have a better way, please tell me, I really need it too

        Let’s talk about the existing shortcomings. First of all, the indexOf function is used multiple times, which may cause performance problems + unsightliness. At the same time, the wrong judgment I made does not cover all situations. If you find bugs during use, you need to eliminate them.

        This method of obtaining the DOM object is definitely not as good as the component directly exposing a method to the outside world, but I have no choice. I hope that the element official can expose the double-click/click event of the table row in the future.

       tip: In addition, you can also directly bind events to elements in the rendering function of each column cell . But the disadvantage is that if you have several headers, you need to bind several events, which may also affect the events of other elements.

Guess you like

Origin blog.csdn.net/m0_64130892/article/details/131643756