el-transfer 数据量大时使用虚拟列表
·
前言
el-transfer 加载几千个数据已经卡得不行了,毕竟页面上存在了 几千多份 dom。
由于时间紧急,打算直接拿源码出来修改。
开始
为了代码不混淆,这里使用 mixins。
有三个文件
virtual-list-mixins.js
export default {
computed: {
contentHeight () {
// 计算滚动条高度
return this.data.length * this.itemHeight
}
},
watch: {
filteredData () {
this.handleScroll()
}
},
mounted () {
this.update()
},
data () {
return {
itemHeight: 30, // 单个高度
virtualList: [] // 渲染数据
}
},
methods: {
update (scrollTop = 0) {
// 获取当前可展示数量
const count = Math.ceil(this.$el.clientHeight / this.itemHeight)
// 取得可见区域的起始数据索引
const start = Math.floor(scrollTop / this.itemHeight)
// 取得可见区域的结束数据索引
const end = start + count
// 计算出可见区域对应的数据,让 Vue.js 更新
this.virtualList = this.filteredData.slice(start, end)
// 把可见区域的 top 设置为起始元素在整个列表中的位置(使用 transform 是为了更好的性能)
this.$refs.content.style.webkitTransform = `translate3d(0, ${start * this.itemHeight}px, 0)`
},
handleScroll (e) {
// 获取当前滚动条滚动位置
const scrollTop = this.$refs.container.scrollTop
this.update(scrollTop)
}
}
}
transfer-panel.vue
...
<div class="list-view"
:class="{ 'is-filterable': filterable }"
ref="container"
@scroll="handleScroll">
<div class="list-view-phantom"
ref="clientHeight"
:style="{ height: contentHeight + 'px' }"></div>
<div ref="content"
class="list-view-content">
<div class="list-view-item">
<el-checkbox-group v-model="checked"
v-show="!hasNoMatch && data.length > 0"
class="el-transfer-panel__list">
<el-checkbox class="el-transfer-panel__item list-view-item"
:style="{ height: itemHeight + 'px' }"
:label="item[keyProp]"
:disabled="item[disabledProp]"
:key="item[keyProp]"
v-for="item in virtualList">
<option-content :option="item"></option-content>
</el-checkbox>
</el-checkbox-group>
</div>
</div>
</div>
...

然后配合一下 css
.list-view {
width: 100%;
height: 100%;
overflow: auto;
position: relative;
&.is-filterable {
height: calc(100% - 62px);
}
}
.list-view-phantom {
position: absolute;
left: 0;
top: 0;
right: 0;
z-index: -1;
}
.list-view-content {
left: 0;
right: 0;
top: 0;
position: relative;
}
.list-view-item {
padding: 6px;
line-height: 30px;
}
/deep/ .el-transfer-panel__list {
height: unset;
}
/deep/.el-transfer-panel__item.el-checkbox .el-checkbox__label {
line-height: 19px;
}
最后
import virtualListMixins from './virtual-list-mixins'
export default {
mixins: [Locale, virtualListMixins]
...
}
完成
然后依旧像往常一样使用它
<template>
<div>
<ElTransfer v-model="value"
filterable
:data="data" />
</div>
</template>
<script>
import ElTransfer from './main.vue'
export default {
components: { ElTransfer },
data () {
const generateData = _ => {
const data = []
for (let i = 1; i <= 10000; i++) {
data.push({
key: i,
label: `备选项 ${i}`
})
}
return data
}
return {
data: generateData(),
value: []
}
}
}
</script>

其他
源代码: Github
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)