关于什么是虚拟列表,这里不赘述。elementui的table组件自己并不支持虚拟列表功能,在对付上100条数据数十列的状况下渲染就很慢,对列表的各类操做都慢,好比点个编辑打开弹窗等等,肉眼可见的延迟。数据越多这样的卡顿越是明显。最近在作的项目就有用到elementui,80%的页面都是各类表格,有的表格要求最低行数100,最高1000,列最少15列,最多达20多列,渲染、操做各项体验很是难受。 因此,虚拟列表势在必行。css
对于超长的表格,在请求到数据以后,先取15条出来交给table组件渲染。剩下的,在滚动列表个时候监听一下表格的滚动条,在逐步添加数据,暴露在视野中的就渲染,其余直接false掉。这里有一个问题须要解决,就是初始下的15条并不能给表格带来符合100条的滚动高度,这里提供两种办法:ajax
在改变每页条数的状况下,须要修改这个高度,考虑到js不容易修改伪元素的高度,因此采用真实标签的作法。json
在进入__mounted__生命周期时,对__table组件初始化__。markdown
let i = document.createElement('i')
i.id = 'vheight'
i.style.width = '0'
i.style.float = 'right'
document.querySelector('.el-table__body-wrapper').append(i)
document.querySelector('.el-table__body').style.float = 'left'
this.tableData2 = {} //tableData2不须要在页面显示,故不放入data中
复制代码
同时,对表格的滚动条添加监听事件app
document.querySelector('.el-table__body-wrapper').addEventListener('scroll', () => {
//xxx
})
复制代码
在拿到数据以后对数据作截断处理ui
$.ajax({
url: url,
type: 'get',
data: {},
dataType: 'json',
success: (data) => {
if (data.code === 1) {
this.tableData2 = data.data // 将这个总的数据存起来
// 拿到数据以后给i加上高度撑出滚动条,42是每行的高度
document.querySelector('#vheight').style.height = this.tableData2.leadsList.length * 42 + 'px'
// 截断的前15条数据放入tableData,交给table组件渲染
this.tableData = {
leadsList: this.tableData2.leadsList.filter((x,i) => i >= 0 && i < (15)),
count: this.tableData2.count
}
}
}
})
复制代码
回过头,添加滚动事件的逻辑this
document.querySelector('.el-table__body-wrapper').addEventListener('scroll', () => {
let s = document.querySelector('.el-table__body-wrapper').scrollTop, h = 42, c = ''
c = Math.floor(s / h)
// 16为横向滚动条的高度
if (s >= (this.tableData2.leadsList.length * 42) - document.querySelector('.el-table__body-wrapper').offsetHeight - 16) {
s = (this.tableData2.leadsList.length * 42) - document.querySelector('.el-table__body-wrapper').offsetHeight
}
if (s <= 0) { s = 0 }
document.querySelector('.el-table__body-wrapper .el-table__body').style.transform = `translateY(${s}px)`
this.tableData = {
leadsList: this.tableData2.leadsList.filter((x,i) => i >= c && i < (c + 15)),
count: this.tableData2.count
}
this.$nextTick(() => {
if (this.selectIdx.length > 0) {
let s = this.tableData.leadsList.map(x => {
if (this.selectIdx.includes(x.leads_id)) {
this.$refs.mulTable.toggleRowSelection(x)
}
return x
})
}
if (this.selectIdx.length > 0 && this.selectIdx.length < this.pageSize) {
setTimeout(() => {
let pro = document.querySelector('.el-table-column--selection')
pro.querySelector('.el-checkbox__input').classList.add('is-indeterminate')
pro.querySelector('.el-checkbox__input').classList.remove('is-checked')
}, 100)
}
})
})
复制代码
到这里,基本的功能初步实现了。接下来就是处理表格的多选。url
在table组件上绑定__select-all、select__两个事件。spa
@select-all="handleSelectionAll" @select="handleSelectionChange"
复制代码
methods 中添加对应的方法和逻辑code
methods: {
// selectIdx存放被勾选的行
handleSelectionChange (val, v) {
let i = this.selectIdx.indexOf(v.leads_id)
if (i !== -1) {
this.selectIdx.splice(i , 1)
} else {
this.selectIdx.push(v.leads_id)
}
},
// 表头全选
handleSelectionAll (val) {
// 有值表示全选,反之亦然
if (val.length > 0) {
this.selectIdx = this.tableData2.leadsList.map(x => x.leads_id)
} else {
this.selectIdx = []
}
},
}
复制代码
在滚动监听事件中处理滚动勾选
this.$nextTick(() => {
if (this.selectIdx.length > 0) {
let s = this.tableData.leadsList.map(x => {
if (this.selectIdx.includes(x.leads_id)) {
this.$refs.mulTable.toggleRowSelection(x)
}
return x
})
}
// 半选下强制修改状态
if (this.selectIdx.length > 0 && this.selectIdx.length < this.pageSize) {
setTimeout(() => {
let pro = document.querySelector('.el-table-column--selection')
pro.querySelector('.el-checkbox__input').classList.add('is-indeterminate')
pro.querySelector('.el-checkbox__input').classList.remove('is-checked')
}, 100)
}
})
复制代码
table组件的__fixed属性__会固定列,可是一个fixed属性它就复制一份表格,影响渲染速度。因此,能够使用css的__sticky属性__来代替。
.fixed-table {
td:first-child, th:first-child {
position: sticky;
left: 0;
z-index: 1;
background: #fff;
}
td:last-child {
position: sticky;
right: 0;
z-index: 1;
background: #fff;
border-left: 1px solid #ebeef5;
}
th:nth-last-child(2) {
position: sticky;
right: 17px;
z-index: 1;
border-left: 1px solid #d1d2d6;
}
.gutter {
width: 17px;
position: sticky;
right: 0;
z-index: 1;
}
}
复制代码
handleSizeChange: function (val) {
this.currentPage = 1
this.pageSize = val
this.selectIdx = []
},
handleCurrentChange: function (val) {
this.selectIdx = []
this.currentPage = val
},
复制代码
document.querySelector('.el-table__body-wrapper').scrollTop = 0
this.selectIdx = []
复制代码