Vue2中使用自定义指令实现el-table虚拟列表的代码示例
作者:程序员张张
引言
上一篇文章我们讲了虚拟列表的实现原理,以及在vue3中的使用实例,感兴趣的友友们可以查看相关内容 传送门。然而,在实际开发中,我们可能会面临其他需求,例如在 el-table
中无法使用分页技术的情况下展示海量数据。这种情况下,页面可能会出现卡顿,严重时甚至可能引发浏览器崩溃。针对这一问题,我们需要寻找其他的解决方案。
创建virtualTable组件
首先新建一个virtualTable.vue
文件,代码如下:
<template> <div style="width: 100%"> <el-table v-virtual-list="virtual" width="100%" height="600" :data="tableData.slice(start, over)"> <el-table-column align="center" prop="date" label="日期" :height="virtual.itemHeight" min-width="180"></el-table-column> <el-table-column align="center" prop="name" label="姓名" :height="virtual.itemHeight" min-width="180"></el-table-column> <el-table-column align="center" prop="address" label="地址" :height="virtual.itemHeight" min-width="180"></el-table-column> </el-table> </div> </template> <script> let timeout = null export default { name: 'virtualTable', data() { return { tableData: [], virtual: { itemHeight: 40, // 每一项高度 scrollClass: '.el-table__body-wrapper', // 有滚动条元素 scrollTop: 0, // 滚动条距离顶部距离 tableHeight: 0 // 可视区高度 } } }, computed: { // 起始下标 start() { return Math.max(Math.ceil(this.virtual.scrollTop / this.virtual.itemHeight - 5), 0) }, // 结束下标 over() { return Math.min( Math.ceil((this.virtual.scrollTop + this.virtual.tableHeight + 1) / this.virtual.itemHeight + 5), this.tableData.length ) }, // 为了保持列表高度完整且滚动条能正常滚 paddingAttr() { let bottom = (this.tableData.length - this.over) * this.virtual.itemHeight let top = this.start * this.virtual.itemHeight return `${top}px 0 ${bottom}px 0` } }, mounted() { this.init() }, methods: { init() { let _arr = [] for (let i = 1; i <= 100000; i++) { _arr.push({ date: '2016-05-02', name: '王小虎' + i, address: `上海市普陀区金沙江路 ${i} 弄` }) } this.tableData = _arr timeout = setTimeout(() => { const target = document.querySelector(this.virtual.scrollClass) this.virtual.tableHeight = target.clientHeight ?? 0 this.setPaddingAttr(target) }) }, // 更新padding属性 setPaddingAttr(target) { let _table = target.querySelector('table') _table.style.padding = this.paddingAttr } }, beforeDestroy() { clearTimeout(timeout) } } </script> <style scoped> ::v-deep th, ::v-deep td { height: 40px; line-height: 40px; padding: 0; } </style>
代码介绍
这边重点说一下里面的关键代码,具体原理可以参考我上一篇文章 传送门
virtual
对象
virtual
对象虚拟列表相关的属性,放在一个对象中方便管理,需要传入到自定义指令中。
timeout = setTimeout(() => {})
为了解决组件初始化时nextTick
中无法获取到正确的clientHeight
。
this.virtual.tableHeight = target.clientHeight ?? 0
组件初始化时获取容器的可视区高度。
this.setPaddingAttr(target)
设置paddingAttr
方法,重新计算padding
,为了确保虚拟列表的渲染效果正确。
tips
当然这里我们可以将其封装成一个公共的组件,如果有相同的需求直接使用当前组件。这里我就不去封装了,感兴趣的友友们可以去尝试一下。
添加自定义指令
// 虚拟列表自定义指令 Vue.directive('virtual-list', { bind(el, bind, vNode) { const that = vNode.context let virtual = bind.value if (virtual) { let target = el.querySelector(virtual.scrollClass) target.addEventListener('scroll', () => { // 更新滚动条位置 that.virtual.scrollTop = target.scrollTop // 重新计算padding that.setPaddingAttr(target) }) } } })
关键代码介绍
const taht = vNode.context
获取当前指令所在组件的上下文this
,以便在后续的代码中访问组件的方法和数据。
let virtual = bind.value
获取组件中传入的值,内部包含虚拟列表的相关信息。
target.addEventListener('scroll', () => {...})
给容器添加滚动监听事件,当用户滚动时触发该事件。
that.virtual.scrollTop = target.scrollTop
更新组件中的 virtual.scrollTop
属性,记录当前滚动条的位置。
that.setPaddingAttr(target)
该方法由当前指令所在组件内部提供。重新计算padding
,为了确保虚拟列表的渲染效果正确。
最终效果如下:
tips
该自定义指令不仅可以在 el-table
中实现虚拟列表,还可以在 el-select
等组件中使用。在实际开发中,只要了解其原理,就可以有效地应用于实际操作中。
文章小尾巴
以上就是Vue2中使用自定义指令实现el-table虚拟列表的代码示例的详细内容,更多关于Vue2 el-table虚拟列表的资料请关注脚本之家其它相关文章!