【VUE】element-ui表格 实现滚动到底部加载更多数据
<template><!-- 滚动加载 --><div class="wrap"><el-tableheight="800":data="visibleData"style="width: 100%"v-load-more.expand="{func: loadmore, target: '.el-table__body-wrapper', delay:
·
背景
调用某系统的远程接口并不支持分页,但是支持分页查询,也就是说分页查了但是不给你返回total数量,你说这是有多坑!!
商量无果,因此解决办法就是我这个后端工程师去实现滚动加载报表的功能…
问题
在element-ui的文档中,存在这么一个指令v-infinite-scroll,但是实际用下来发现,指令只能作用于当前绑定的元素上 文档
初步实现-DEMO
经过我一番搜索,找到了一篇真的不错的文章:
element-ui表格 实现滚动到底部加载更多
这篇文章基本上可以解决我的问题,但是在实操过程中,会发现作者写的滚动到底部加载,会有自适应问题,因此我这边调整了一下distance
的参数就解决了。
我这边整了一个element的demo,可以直接拷贝使用:
<template>
<!-- 滚动加载 -->
<div class="wrap">
<el-table
height="600"
:data="visibleData"
style="width: 100%"
v-load-more.expand="{func: loadmore, target: '.el-table__body-wrapper', delay: 300}"
:load-more-disabled="disabledLoad">
<el-table-column
prop="id"
label="ID">
</el-table-column>
<el-table-column
prop="date"
label="日期">
</el-table-column>
<div slot="append" style="text-align:center;">{{content}}</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 {
data () {
return {
visibleCount: 30,
tableData: [],
content: '滚动到底部加载更多'
}
},
created() {
let count = 120
while(count >= 0) {
count--
this.tableData.push({
id: count,
date: "2016-05-02"
})
}
},
computed: {
// 是否禁止无限加载
disabledLoad() {
return false
},
visibleData() {
return this.tableData.slice(0, Math.min(this.tableData.length, this.visibleCount))
}
},
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)
console.info(targetEl)
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) {
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
}
}
}
},
methods: {
loadmore () {
console.log('滚动到底部了')
this.visibleCount += 10
if(this.visibleCount >= this.tableData.length){
this.content = '暂无更多数据'
}
}
}
}
</script>
最终升级版本-表格滚动组件
我在想,这个表格滚动加载实现起来并不轻松,如果可以抽象成一个组件来使用,会更加灵活。
因此在上面demo的基础上我做了一些改动:
- 动态加载表格列
- 自定义初始化数量
- 不在初始化的时候加载全部数据,而是在滚动到底部的时候进行加载
组件代码scrollTable.vue
<!-- 滚动加载表格组件 -->
<template>
<div class="wrap">
<el-table
height="600"
:data="visibleData"
style="width: 100%"
v-load-more.expand="{func: loadmore, target: '.el-table__body-wrapper', delay: 300}"
:load-more-disabled="disabledLoad">
<!-- 动态列表格 -->
<el-table-column :prop="index" :label="item" sortable v-for="(item, index) in tableHeader"
:key="index">
</el-table-column>
<!-- 底部文案 -->
<div v-if="visibleData.length>=15" slot="append" style="margin-top:10px; margin-bottom:10px; text-align:center; font-size:15px ">{{content}}</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 {
props:{
//表格列信息
tableHeader: {
type: Object,
required: true
},
//表格数据 注意需要增量(第一次是30条 第二次为30+10条....)
tableData: {
type: Array,
required: true
},
//用于下拉查询新一页的数据信息 入参(页码,页数大小)
method: {
type: Function
},
//初始行数(最好不要小于当前页面size,否则滚动下载有失效的可能,且size必须为10的倍数)
initCount: {
type: Number,
required: true
}
},
mounted() {
},
data () {
return {
visibleCount: 30,
content: '滚动到底部加载更多',
pageIndex: 1,
pageSize: 10,
}
},
created() {
console.info("创建了...")
this.visibleCount = this.initCount
this.pageIndex = this.initCount/this.pageSize
},
computed: {
// 是否禁止无限加载
disabledLoad() {
return false
},
visibleData() {
return this.tableData.slice(0, Math.min(this.tableData.length, this.visibleCount))
}
},
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) {
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) {
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
}
}
}
},
methods: {
async loadmore () {
console.log('滚动到底部了')
this.pageIndex++
await this.method(this.pageIndex ,this.pageSize)
this.visibleCount += 10
if(this.visibleCount > this.tableData.length){
this.content = '暂无更多数据'
}
},
}
}
</script>
使用方式:
因为涉及到公司业务代码,因此我这里把业务代码去掉了(伪代码,不能直接copy运行)
<template>
<div>
<div class="container">
<el-form :inline="true" :model="query" class="demo-form-inline">
<!-- 查询条件 -->
<!----------------->
<el-form-item>
<el-button type="primary" @click="handleSearch" :loading="loading">查询</el-button>
<el-button type="primary" @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
<!-- 动态加载数据 -->
<scroll-table v-if="hackReset" :tableHeader="tableHeader" :tableData="tableData" :method="scrollMethod" :initCount="initCount"></scroll-table>
</div>
</div>
</template>
<script>
import scrollTable from '../share/scrollTable';
export default {
name: 'StockPage',
components:{
scrollTable
},
data() {
return {
query: {
info: '',
},
//表头
tableHeader:{
id: "ID",
date: "日期",
page: 1,
size: 20
},
//表数据信息
tableData:[], //当前查询条件分页累加数据信息
dataList:[], //分页查询数据信息
initCount:20, //初始化行数
hackReset: true,//重新刷新子组件渲染
}
},
created() {
},
methods: {
//查询
handleSearch() {
//点击查询,需要重新渲染组件
this.rebuileComponents()
},
//动态加载表数据方法
async scrollMethod(pageIndex, pageSize){
this.query.page = pageIndex
this.query.size = pageSize
if(this.checkQuery()){
let result = await findPage(this.query)
if (result) {
this.dataList = result.list
//累加
if(this.dataList.length>0){
let i =0 ;
for(i;i< this.dataList.length ;i++){
this.tableData.push(this.dataList[i])
}
}
}
}
}
},
//校验
checkQuery(){
//校验查询条件
return true;
},
//强制重新加载子组件
rebuileComponents() {
// 销毁子标签
this.hackReset = false;
// 重新创建子标签
this.$nextTick(() => {
this.hackReset = true;
});
},
//重置
async handleReset() {
},
}
</script>
<style scoped>
</style>
如果文章对你有帮助,不要忘了给我点个赞吼( ̄▽ ̄)~
欢迎关注我的微信公众号:松鼠技术站
更多推荐
已为社区贡献7条内容
所有评论(0)