背景:
需要在el-tablel里实现滚动到底部加载更多数据
问题:使用element自带的无限滚动,但是实际用下来发现,指令只能作用于当前绑定的元素上,如下:
<ul class="infinite-list" v-infinite-scroll = "load" style="overflow:auto; height: 200px;">
<li v-for="(item, index) in tableData" :key="index">{{ item.name }}</li>
</ul>
对于不是真正的出现滚动条的标签,却无能为力
<el-table
border
height="400"
v-infinite-scroll="load"
:data="tableData"
>
<el-table-column prop="date" label="日期" width="180"></el-table-column>
<el-table-column prop="name" label="姓名" width="150"></el-table-column>
<el-table-column prop="address" label="地址" width="240"></el-table-column>
</el-table>
标签不是真正的容器,绑定了指令,无法生效
实现
第一步:判断滚到底部
const { scrollTop, scrollHeight, clientHeight } = targetEl
if(scrollHeight === scrollTop + clientHeight) {
console.log('到底部了!')
}
简洁版:
export default {
name: 'load-more',
bind(el, binding, vnode) {
binding.handler = function(){
const {scrollTop, scrollHeight, clientHeight} = el
if (scrollHeight === scrollTop + clientHeight) {
binding.value && binding.value()
}
}
el.addEventListener('scroll', binding.handler)
},
unbind(el, binding) {
el.removeEventListener('scroll', binding.handler)
el = null
}
}
把写好的指令在组件内注册后,即可生效。
我们的指令能够支持:
完整代码:
<template>
<div>
<el-table
border
height="400"
:data="visibleData"
:row-key="getRowKeys"
v-load-more.expand="{func: loadmore, target: '.el-table__body-wrapper', delay: 300}"
:load-more-disabled="disabledLoad"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" :reserve-selection="true" width="55"> </el-table-column>
<el-table-column prop="date" label="日期" width="180"></el-table-column>
<div slot="append" style="text-align: center;">滚动到底部加载更多</div>
</el-table>
</div>
</template>
<script>
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)
}
}
export default {
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 = 0, func, delay = 200 } = binding.value
if (typeof target !== 'string') return
let targetEl = el.querySelector(target)
if (!targetEl) {
console.log('找不到容器')
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) {
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
}
}
}
},
data() {
return {
visibleCount: 10,
tableData: [
{id: '234', date: '2016-06-01'},
{id: '34', date: '2016-06-01'},
{id: '24', date: '2016-06-01'},
{id: '23242', date: '2016-06-01'},
{id: '23243', date: '2016-06-01'},
{id: '23244', date: '2016-06-01'},
{id: '23245', date: '2016-06-01'},
{id: '23246', date: '2016-06-01'},
{id: '23247', date: '2016-06-01'},
{id: '23248', date: '2016-06-01'}
],
multipleSelection: []
}
},
created() {
let count = 1
while(count >= 0) {
count--
this.tableData.push(
{ id: '1213', date: '2016-05-02' },
{ id: '11123', date: '2016-05-02' },
{ id: '123023', date: '2016-05-02' },
{ id: '1253', date: '2016-05-02' },
{ id: '1243', date: '2016-05-02' },
{ id: '1263', date: '2016-05-02' },
{ id: '1273', date: '2016-05-02' },
{ id: '1283', date: '2016-05-02' },
{ id: '1293', date: '2016-05-02' },
{ id: '1203', date: '2016-05-02' },
{ id: '1323', date: '2016-05-02' },
{ id: '1423', date: '2016-05-02' },
{ id: '1523', date: '2016-05-02' },
{ id: '1623', date: '2016-05-02' },
{ id: '1723', date: '2016-05-02' },
{ id: '1823', date: '2016-05-02' },
{ id: '1923', date: '2016-05-02' },
{ id: '1023', date: '2016-05-02' },
{ id: '12323', date: '2016-05-02' },
{ id: '134323', date: '2016-05-02' }
)
}
},
computed: {
disabledLoad() {
return false
},
visibleData() {
return this.tableData.slice(0, Math.min(this.tableData.length, this.visibleCount))
}
},
methods: {
loadmore() {
console.log('滚动到底部了');
this.visibleCount += 10;
},
handleSelectionChange(val) {
this.multipleSelection = val;
console.log(this.multipleSelection)
const ids = this.multipleSelection.map(item => {
return item.id
})
console.log(ids)
},
getRowKeys(row) {
return row.id
}
}
}
</script>
注:
el-table
里的:row-key="getRowKeys"
和@selection-change="handleSelectionChange"
配合el-table-column
里的:reserve-selection="true"
实现了无限加载的同时记住已选内容
参考文章:
element-ui表格 实现滚动到底部加载更多