以下为前台模拟滚动加载数据,实际开发应用中,可在 tableLoad 函数中调用接口向后台请求下一页数据
<template>
<a-table
:columns="staffColumns"
:dataSource="dataSource"
:pagination="false"
:rowKey="record => record.staffId"
ref="tableRef"
:scroll="{
x: 400,
y: 545
}"
v-loadMore.expand="{ func: tableLoad, target: '.ant-table-body', delay: 300, distance: 10 }"
>
</a-table>
</template>
<script>
import { reactive,toRefs,ref } from 'vue'
import { staffColumns } from '../../columns'
export default {
setup() {
const dataSource = ref([]) //列表数据
const tableRef = ref(null)
const state = reactive({
currentPage:1, //当前页码
total:[], //列表总数据
start: 0, //数据截取开始位置
})
//加载更多
const tableLoad = () => {
//超过最大页数不继续执行
if (state.currentPage>= Math.ceil(state.total.length / 10)) {
tableRef.value.$el.setAttribute('load-more-disabled', 'true')
return
}
state.currentPage += 1
state.start += 10
dataSource.value = [...dataSource.value, ...state.total.slice(state.start, state.start + 10)]
}
return{
tableLoad,
dataSource,
tableRef,
...toRefs(state),
}
}
}
</script>
使用vue3 自定义指令 实现滚动事件监听
注册自定义指令
// src/utils/loadMore.js
import { Directive, App } from 'vue'
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)
}
}
const loadMore = {
mounted(el, binding, vnode) {
//为dom节点设置 load-more-disabled 属性
el.setAttribute('load-more-disabled', 'false')
const { expand } = binding.modifiers
// 使用更丰富的功能,支持父组件的指令作用在指定的子组件上
if (expand) {
/**
* target 目标DOM节点的类名
* distance 减少触发加载的距离阈值,单位为px
* func 触发的方法\-0
* delay 防抖时延,单位为ms
* load-more-disabled 是否禁用无限加载
*/
let { target, distance = 0, func, delay = 200 } = binding.value
if (typeof target !== 'string') return
let targetEl = el.querySelector(target)
console.log('targetEl', targetEl)
if (!targetEl) {
console.log('找不到容器')
return
}
binding.handler = function() {
const { scrollTop, scrollHeight, clientHeight } = targetEl
let disabled = el.getAttribute('load-more-disabled')
// disabled = vnode[disabled] || disabled
if (scrollHeight <= scrollTop + clientHeight + distance) {
if (disabled == 'true') return
func && func()
}
}
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)
}
},
unmounted(el, binding) {
console.log('卸载了 ')
let { arg } = binding
// 使用更丰富的功能,支持父组件的指令作用在指定的子组件上
if (arg === 'expand') {
/**
* target 目标DOM节点的类名
* offset 触发加载的距离阈值,单位为px
* method 触发的方法
* delay 防抖时延,单位为ms
*/
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
}
}
}
export function setupLoadMoreDirective(app) {
app.directive('loadMore', loadMore)
}
export default loadMore
// main.js
import { createApp } from 'vue'
import App from './App.vue' // 入口文件
import { setupLoadMoreDirective } from '@/utils/loadMore.js' //表格滚动加载
const app = createApp(App)
setupLoadMoreDirective(app)