背景:由于列表数据过多,上千甚至上万条数据,如果全部加载,页面交互很卡,所以改为滚动加载,原理就是分页加载。
- 监听左侧滚动条滚动到底
- 监听左侧搜索条件的变化
- 监听左侧全选是否选中
- 搜索条件如果从接口查询,过滤函数永远返回true
- 手动使滚动条置顶
- 判断是否点击全选(选中)
<template>
<div id="transfer-form">
<el-transfer
ref="myTransfer"
:titles="['全选', '全选']"
:props="{key: 'key',label: 'name'}"
:left-default-checked="leftDefaultChecked"
filterable
:filter-method="scrollTransferFilterMethod"
filter-placeholder="请输入需要检索的表名"
@change="transferChange"
v-model="selectedData"
:data="tableList">
</el-transfer>
</div>
</template>
<script>
export default {
data () {
return {
tableList: [],
leftDefaultChecked: [],
selectedData: [],
selectedDataMap: new Map(), // 缓存选中数据,解决在改变搜索条件时,列表清空,右侧选中数据也会丢失
scrollQuery: '',
scrollPageSize: 20,
scrollPageNum: 1,
scrollPageTotal: 0,
// this.$watch监听返回的取消监听函数,重新监听前执行取消
scrollQueryWatch: null,
scrollAllCheckedWatch: null
}
},
mounted () {
this.watchScroll()
},
methods: {
/* 监听左侧滚动条 */
watchScroll () {
const me = this
const scrollContainer = this.getScrollContainer()
scrollContainer && scrollContainer.addEventListener('scroll', debounce(function () {
// 在分辨率高的屏幕上,scrollTop可能会出现小数使左边的值小于右边的值,永远不会触发判断
const scrollTop = Math.ceil(scrollContainer.scrollTop)
const clientHeight = scrollContainer.clientHeight
const scrollHeight = scrollContainer.scrollHeight
if (!clientHeight || !scrollHeight) return
if (scrollTop + clientHeight >= scrollHeight) {
// 滚动到底,加载下一页数据,因为数据量比较大,改成分页加载
me.scrollLoadList()
}
}, 100))
},
getScrollContainer () {
/* id自定义 */
const packageDom = document.getElementById('transfer-form')
const scrollContainer = packageDom.querySelector('.el-transfer-panel__list')
return scrollContainer
},
scrollLoadList () {
if (this.scrollPageTotal > this.tableList.length) {
this.scrollPageNum += 1
// this.searchList()
}
},
/* 手动使滚动条置顶 */
scrollToTop () {
const scrollContainer = this.getScrollContainer()
scrollContainer.scrollTop = 0
// scrollContainer.scrollTo({
// top: 0
// })
},
// 监听左侧搜索条件的变化
watchLeftPanelQuery () {
const me = this
this.scrollQueryWatch && this.scrollQueryWatch()
const transferVm = this.$refs.myTransfer
transferVm.$refs.leftPanel.query = ''
this.scrollQuery = ''
this.scrollQueryWatch = transferVm.$refs.leftPanel.$watch('query', function (val) {
me.scrollQuery = val
me.scrollDebounceQuery()
})
},
// 监听左侧全选是否选中
watchLeftAllChecked () {
const me = this
this.scrollAllCheckedWatch && this.scrollAllCheckedWatch()
const transferVm = this.$refs.myTransfer
this.scrollAllCheckedWatch = transferVm.$refs.leftPanel.$watch('allChecked', function (val) {
...
})
},
/* 搜索条件如果从接口查询,过滤函数永远返回true */
scrollTransferFilterMethod (query, item) {
return true
},
async leftTransferChange (keys) {
// 判断是否点击全选(选中)
if (keys.length + this.selectedData.length === this.tableList.length) {
}
},
/* 缓存选中的数据(移到右边的数据) */
transferChange (keys) {
keys.forEach(key => {
const item = this.tableList.find(o => o.key === key)
this.selectedDataMap.set(key, item)
})
}
}
}
</script>
这里实现的是后端分页,就是每次都要请求接口。如果一次性获取到所有数据,前端只不过模拟分页请看这篇文章。