使用的ui组件库是element-ui
以下代码只是我的一种优化思路,我目前没法解决虚拟滚动的同时实现表格的合并行操作,不过可以通过这种思路解决简单的表格数据结构,但是数据量多造成的渲染dom太耗时,其他,探讨一下我实现的时候遇到的问题:
整个思路都是通过 paddingBottom 属性 和 paddingTop属性值修改进行数据的显示,以及计算 scrollTop属性值 与行的高度尺寸 还有 数组截取slice方法使用时的下表起始位置 之间的关系实现的一个简陋的虚拟滚动的代码封装在一个局部的自定义指令里
import * as Mock from 'mockjs'
const { Random } = Mock
export default {
name: 'App',
data () {
return {
list: [],
columns: [],
start: 0,
over: 5
}
},
mounted () {
function g (num) {
return Array.from({ length: num }).reduce((res, _, id) => {
return res.concat({
id,
name: Random.cname(),
score: Random.natural(10, 10000)
})
}, [])
}
setTimeout(() => {
this.list = g(11)
})
},
components: {},
methods: {},
// 局部的指令
directives: {
myScrollbar: {
bind: function (dom = document.documentElement, _, vnode) {
setTimeout(() => {
/* 获取当前使用指令的组件this引用 */
const self = vnode.context
const headerWrapper = dom.querySelector('.el-table__header-wrapper')
const scrollView = dom.querySelector('.el-table__body-wrapper')
const content = scrollView.querySelector('.el-table__body')
/* 如果有固定列的业务 取出fixedView获取高度 */
const fixedView = dom.querySelector('.el-table__fixed-body-wrapper')
const fixedContent = fixedView.querySelector(
'.el-table__fixed .el-table__body'
)
// 表头高度
const HEADER_HEIGHT = headerWrapper.clientHeight
// 表内容区域高度
let table_body_height = scrollView.clientHeight
// 判断是否有固定列
const IS_FIXED = Boolean(fixedView && fixedContent)
const row = scrollView.querySelector('tr.el-table__row')
const row_height = row?.clientHeight ?? 52
/* 始终渲染的行数 */
let row_count = 5
const SAFE_AREA_HEIGHT = 1 // 预留区域使滚轮呈现
/* 核心步骤 数组的元素显示在区域内部 */
function scrollHandler () {
const totalHeight = self.list.length * row_height
content.style.paddingTop = `${Math.min(
scrollView.scrollTop,
totalHeight - scrollView.clientHeight
)}px`
content.style.paddingBottom = `${Math.max(
totalHeight - scrollView.clientHeight - scrollView.scrollTop,
0
)}px`
if (IS_FIXED) {
fixedView.style.height = `${scrollView.clientHeight}px`
fixedContent.style.paddingTop = `${Math.min(
scrollView.scrollTop,
totalHeight - scrollView.clientHeight
)}px`
fixedContent.style.paddingBottom = `${Math.max(
totalHeight - scrollView.clientHeight - scrollView.scrollTop,
0
)}px`
}
self.start = Math.min(
Math.ceil(scrollView.scrollTop / row_height),
self.list.length - row_count
)
self.over = row_count + self.start
}
/* 获取传入的默认总高度 max-height height 行内样式*/
/* 初始化高度 el-table 以及根据原有的逻辑计算得出标题高度,内容区域高度 */
function setSize () {
const reg = /(\d+)(\w+)$/i
const DOM_HEIGHT = ['max-height', 'maxHeight', 'height'].reduce(
(res, key) => {
let h = dom.style[key]
h = h ? h.match(reg)[1] : res
return Number(h)
},
500
)
table_body_height = DOM_HEIGHT - HEADER_HEIGHT
scrollView.style.height = `${table_body_height}px`
content.style.paddingBottom = `${SAFE_AREA_HEIGHT}px`
if (!IS_FIXED) return
fixedView.style.height = `${table_body_height}px`
fixedContent.style.paddingBottom = `${SAFE_AREA_HEIGHT}px`
}
/* 根据row_count 计算得出 start over响应式数据 */
function setData () {
row_count = Math.ceil(table_body_height / row_height)
self.start = 0
self.over = self.start + row_count
}
function _init () {
setSize()
setData()
scrollView.addEventListener('scroll', scrollHandler)
}
_init()
})
}
}
}
}
template 代码片段
<div >
<el-table :data="list.slice(start, over)" v-my-scrollbar :height="500">
<el-table-column
label="编号"
fixed
prop="id"
width="200"
></el-table-column>
<el-table-column
label="姓名"
fixed
prop="name"
width="500"
></el-table-column>
<el-table-column label="成绩" prop="score" width="200"></el-table-column>
<el-table-column label="操作" width="500">
<el-button size="mini">编辑</el-button>
<el-button size="mini" type="danger">删除</el-button>
</el-table-column>
</el-table>
</div>
效果图:
问题1: 固定列的遮罩层内容无法与表格内容对其
我的解决方法:将固定列的遮罩层高度与内容区域的高度保持一直