当后台返回数据量较大时,如果全部加载,性能会有巨大的影响。如何优化长列表也是前端工程师最为头疼的一个问题。现总结一种使用vue自定义指令来实现长列表性能优化的方案。
1. html模板:注意要写在需要优化元素的父级元素
// 条件判断时
<el-table stripe border height="550"
:data="tableData"
style="width: 100%"
v-load-more.expand="{func: loadmore, target: '.el-table__body-wrapper', delay: 300}"
:load-more-disabled="disabledLoad"
@selection-change="handleSelectionChange"
@select-all="handleSelectAll"
>
</el-table>
2. 自定义下拉显示更多指令
directives: {
'load-more': {
bind (el, binding, vnode) {
const {
expand
} = binding.modifiers
// 使用更丰富的功能,支持父组件的指令作用在指定的子组件上
if (expand) {
/**
* target 目标DOM节点的类名
* distance 减少触发加载的距离阈值,单位为px
* func 触发的方法
* delay 防抖时延,单位为ms
* load-more-disabled 是否禁用无限加载
*/
let {
target,
distance = 1,
func,
delay = 200
} = binding.value
if (typeof target !== 'string') return
let targetEl = el.querySelector(target)
if (!targetEl) {
return
}
binding.handler = debounce(function () {
const {
scrollTop,
scrollHeight,
clientHeight
} = targetEl
let disabled = el.getAttribute('load-more-disabled')
disabled = vnode[disabled] || disabled
if (scrollHeight <= scrollTop + clientHeight + distance) {
if (disabled) return
func && func()
}
}, delay)
targetEl.addEventListener('scroll', binding.handler)
} else {
binding.handler = debounce(function () {
const {
scrollTop,
scrollHeight,
clientHeight
} = el
if (scrollHeight === scrollTop + clientHeight) {
binding.value && binding.value()
}
}, 200)
el.addEventListener('scroll', binding.handler)
}
},
unbind (el, binding) {
let {
arg
} = binding
// 使用更丰富的功能,支持父组件的指令作用在指定的子组件上
if (arg === 'expand') {
const {
target
} = binding.value
if (typeof target !== 'string') return
let targetEl = el.querySelector(target)
targetEl && targetEl.removeEventListener('scroll', binding.handler)
targetEl = null
} else {
el.removeEventListener('scroll', binding.handler)
el = null
}
}
}
},
3. script标签中定义相关方法
// 加载显示更多请求
loadmore () {
if (this.nextPage) {
getActivedDeviceList({
boardModel: '',
departmentId: '',
deviceStatus: this.idleStatus,
pageNum: this.nextPage,
pageSize: 20,
searchKey: ''
}).then(res => {
if (res && res.result.length) {
this.nextPage = res.nextPage
this.tableData.push(...res.result)
}
})
}
},
// 防抖
const debounce = function (func, delay) {
let timer = null
return function () {
if (timer) clearTimeout(timer)
timer = null
let self = this
let args = arguments
timer = setTimeout(() => {
func.apply(self, args)
}, delay)
}
}