關於什麼是虛擬列表,這裏不贅述。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 = []
複製代碼