滚动触底加载方案
单页面表格,不涉及多tab不涉及v-if可以使用插件el-table-infinite-scroll(2.0版本为vue2版本,一堆bug)
<template>
<el-table v-load-more.expand="{ func: loadMore, target: '.el-table__body-wrapper', delay: 300 }" :data="data"
style="width: 100%" :height="height" header-align="center" v-bind="$attrs">
<el-table-column type="index" width="50" label="序号" v-if="columnObj.selection">
</el-table-column>
<el-table-column :show-overflow-tooltip="columnObj.showToolTip" v-for="(column, columnIndex) in columnData"
:key="columnIndex" :prop="column.prop" :label="column.label" :width="column.width" :align="columnObj.align">
<template slot-scope="scope">
<!-- 带button的操作栏 -->
<div v-if="column.isOperation && buttonGroup">
<span v-for="item in buttonGroup">
<el-button @click="item.buttonClick(scope.row)" :type="item.type"
:style="{ color: item.color }">{{
item.label }}</el-button>
</span>
</div>
<!-- 可跳转/点击 -->
<span class="pointer" v-else-if="column.isJump" @click="column.jumpClick(scope.row)">
{{ scope.row[column.prop] }}
</span>
<!-- 时间格式 -->
<span v-else-if="column.isDate">
{{ parseTime(scope.row[column.prop]) }}
</span>
<!-- 映射字段 -->
<span v-else-if="column.isMapText">
{{ scope.row[column.prop] | mapTextFilter(column.list) }}
</span>
<!-- 自定义项 -->
<span v-else-if="columnObj.cusTomFields.includes(column.prop)">
<slot :name="column.prop" :row="scope.row"></slot>
<!-- 示例 <template slot="status" slot-scope="data"> {{ data.row.status }} </template> -->
</span>
<!-- 可双击 -->
<span class="pointer" v-else-if="column.isDblClick"
@dblclick="column.dblclick(scope.row, scope.column, scope.$index)">
{{ scope.row[column.prop] }}
</span>
<!-- 默认显示 -->
<span v-else> {{ scope.row[column.prop] }}</span>
</template>
</el-table-column>
</el-table>
</template>
接收参数
props: {
data: {
type: Array,
default: () => [],
require: true
},
/**
* @description: 列配置
* @author: wxy
* @param {*} selection false 默认显示序号
* @param {*} showToolTip true 默认超出显示...
* @param {*} align true 默认居中
* @param {*} cusTomFields [] 需要自定义的列表项
* @return {*}
*/
columnObj: {
type: Object,
default: () => {
return {
}
},
require: true
},
height: {
type: String | Number,
default: null
}
},
映射逻辑
filters: {
mapTextFilter(e, list) {
const obj = list.find(item => {
return item.value === e
})
return obj?.label
}
},
computed: {
columnData() {
let { columnData } = this.columnObj
// 无操作按钮时不显示操作栏
if (this.buttonGroup.length < 1) {
columnData = columnData.filter(item => {
return item.isOperation !== true
})
}
return columnData
},
buttonGroup() {
// 操作栏 过滤掉无权限的按钮(auth)
const { columnData } = this.columnObj
const obj = columnData.find(item => {
return item.isOperation
})
const res = obj?.operation.filter(item => {
return item.auth !== false
})
return res || []
}
},
增加默认值
watch: {
columnObj: {
handler (val) {
if (val.align === undefined) val.align = 'center'
if (val.selection === undefined) val.selection = false
if (val.showToolTip === undefined) val.showToolTip = true
if (val.cusTomFields === undefined) val.cusTomFields = []
},
immediate: true
},
},
触底加载更多指令注册(亲测比插件好用)
const debounce = function (func, delay) {
let timer = null
return function () {
if (timer) clearTimeout(timer)
timer = null
const self = this
const args = arguments
timer = setTimeout(() => {
func.apply(self, args)
}, delay)
}
}
directives: {
'load-more': {
bind(el, binding, vnode) {
const { expand } = binding.modifiers
// 使用更丰富的功能,支持父组件的指令作用在指定的子组件上
if (expand) {
/**
* target 目标DOM节点的类名
* distance 减少触发加载的距离阈值,单位为px
* func 触发的方法
* delay 防抖时延,单位为ms
* load-more-disabled 是否禁用无限加载
*/
const { target, distance = 1, func, delay = 200 } = binding.value
if (typeof target !== 'string') return
const targetEl = el.querySelector(target)
if (!targetEl) {
console.log('Container Not Found')
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 = helper.debounce(function () {
const { scrollTop, scrollHeight, clientHeight } = el
if (scrollHeight === scrollTop + clientHeight) {
binding.value && binding.value()
}
}, 200)
el.addEventListener('scroll', binding.handler)
}
},
unbind(el, binding) {
const { 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
}
}
}
},
methods: {
loadMore() {
let nowTime = new Date().getTime()
let diffTime = (nowTime - this.lastTime) / 1000
if (diffTime > 2 && this.isFirstLoad) {
console.log('执行loadMore','用时间戳避免调用两次');
this.$emit('loadMore')
}
this.lastTime = nowTime
}
},