说明
自用
一、自定义指令实现
参考:
template
<template>
<el-table
size="mini"
:height="height"
highlight-current-row
v-loading="loading"
v-loadmore="loadMore"
:data="tableData"
>
<slot></slot>
<template slot="append">
<div class="no-more">
我~是有底线的 (~ ̄▽ ̄)~
</div>
</template>
</el-table>
</template>
script
export default {
name: 'WbTable',
// 自定义指令
// vue 官方文档:https://cn.vuejs.org/v2/guide/custom-directive.html
directives: {
loadmore: {
bind (el, binding) {
const selectWrap = el.querySelector('.el-table__body-wrapper')
selectWrap.addEventListener('scroll', function () {
let sign = 100
const scrollDistance = this.scrollHeight - this.scrollTop - this.clientHeight
if (scrollDistance <= sign) {
binding.value()
}
})
}
}
},
props: {
// 服务端列表数据接口名称
url: {
type: String,
required: true
},
// 服务端列表数据接口请求参数
params: {
type: Object,
required: true
}
},
data () {
return {
tableData: [],
loading: false,
total: 0
}
},
created () {
this.limit = this.params.limit ? this.params.limit : 8
this.offset = this.params.offset ? this.params.offset : 0
// 根据单元格最小高度计算表格高度
this.height = this.limit * 45
this.append(this.params)
},
methods: {
append (params) {
this.loading = true
this.$http[this.url]({
...params,
offset: this.offset,
limit: this.limit
})
.then(result => {
this.tableData = [
...this.tableData,
...result.data.rows
]
console.log(this.tableData)
this.total = result.data.total || 0
})
.finally(() => {
this.loading = false
})
},
reload () {
// 刷新重置 offset 和表格
this.params.offset = 0
this.tableData = []
// api动态加载完 开始重新请求数据
this.$nextTick(() => {
this.init(this.params)
})
},
// 滚动事件
loadMore () {
const newOffset = this.offset + this.limit
if (newOffset < this.total && !this.loading) {
this.offset = newOffset
this.append(this.params)
}
}
}
}
-
3.效果
二、与el-infinite-scroll
结合
有大佬已经实现了,查看:
element-ui 的 el-table 上使用无限滚动加载(与自带的 infinite-scroll 结合):https://blog.csdn.net/baidu_27769027/article/details/101924676
GitHub代码:https://github.com/yujinpan/el-table-infinite-scroll/blob/master/src/directives/table-infinite-scroll.js
三、 使用vue-infinite-loading
实现滚动加载
参考:
官方文档(中文):https://peachscript.github.io/vue-infinite-loading/zh/
vue elmentui table 滚动加载:https://www.jianshu.com/p/48df3fd85dd6
1. 安装
注意:vue-infinite-loading2.0只能在Vue.js2.0中使用。如果你想在Vue.js1.0中使用,请安装vue-infinite-loading1.3版本
npm install vue-infinite-loading --save
2.引入
import InfiniteLoading from 'vue-infinite-loading'
export default {
name: 'WbTable',
components: {InfiniteLoading}
}
3.完整使用
template
<template>
<el-table
size="mini"
:height="height"
highlight-current-row
v-loading="loading"
:data="tableData"
>
<slot></slot>
<template slot="append">
<!--
@infinite: 滚动事件回调函数,当滚动到距离滚动父元素底部特定距离的时候,会被调用
distance: 这是滚动的临界值。default: 100; 如果到滚动父元素的底部距离小于这个值,那么 loadMore 回调函数就会被调用。
spinner: 通过这个属性,你可以选择一个你最喜爱旋转器作为加载动画
'default' | 'bubbles' | 'circles' | 'spiral' | 'waveDots'
direction: 如果你设置这个属性为top,那么这个组件将在你滚到顶部的时候,调用on-infinite函数
'top' | 'bottom'
forceUseInfiniteWrapper: (boolean | string) 强制指定滚动容器,使用CSS 选择器
identifier: 识别号,改变时刷新
-->
<infinite-loading
@infinite="loadMore"
ref="infiniteLoading"
:distance="100"
spinner="bubbles"
:identifier="infiniteId"
force-use-infinite-wrapper=".el-table__body-wrapper">
<!-- orce-use-infinite-wrapper 属性在存在多个 el-table 需要更详细的css选择器 -->
<div class="no-more" slot="no-more">
我~是有底线的 (~ ̄▽ ̄)~
</div>
<div class="no-more" slot="no-results">
暂无结果 Ծ‸Ծ
</div>
<div class="no-more" slot="error">
出错了 (╯‵□′)╯︵┻━┻
</div>
</infinite-loading>
</template>
</el-table>
</template>
script
import InfiniteLoading from 'vue-infinite-loading'
export default {
name: 'WbTable',
components: {InfiniteLoading},
props: {
// 服务端列表数据接口名称
url: {
type: String,
required: true
},
// 服务端列表数据接口请求参数
params: {
type: Object,
required: true
}
},
data () {
return {
tableData: [],
loading: false,
total: 0,
isOver: false,
infiniteId: new Date()
}
},
created () {
this.limit = this.params.limit ? this.params.limit : 8
this.offset = this.params.offset ? this.params.offset : 0
// 根据单元格最小高度计算表格高度
this.height = this.limit * 45
},
methods: {
// 滚动事件
async loadMore ($state) {
this.loading = true
if (!this.isOver) {
await this.$http[this.url]({
...this.params,
offset: this.offset,
limit: this.limit
})
.then((result) => {
this.tableData = [
...this.tableData,
...result.data.rows
]
this.total = result.data.total || 0
if (this.total <= this.tableData.length) {
this.isOver = true
$state.complete() // 全部加载完成
} else {
$state.loaded() // 单个数据加载完毕
this.offset = this.offset + this.limit // 设置下一页
}
console.log(this.tableData, this.total)
})
.finally(() => {
this.loading = false
})
}
},
reset () {
this.offset = 0
this.tableData = []
this.infiniteId += 1
}
}
}
四、手动加载下一页
运用el-table
的插槽append
设置一个加载按钮,手动触发页面加载
template
<template>
<el-table
size="mini"
highlight-current-row
:height="tableHeight"
:data="tableData"
v-loading="loading"
empty-text="暂无数据 Ծ‸Ծ"
>
<slot></slot>
<template slot="append" v-if="total > limit">
<div v-if="loading" class="table-append loading">
<i class="fa fa-spinner fa-pulse fa-2x fa-fw"></i>
</div>
<div v-else-if="!isOver && !noMore && !isError" class="table-append next" @click="nextPage">
<i class="fa fa-angle-double-down fa-2x fa-fw arrow"></i>
</div>
<div v-else class="table-append ending">
<span v-show="isError">出错了 (╯‵□′)╯︵┻━┻</span>
<span v-show="noMore">暂无数据 Ծ‸Ծ</span>
<span v-show="isOver">我~是有底线的 (~ ̄▽ ̄)~</span>
</div>
</template>
</el-table>
</template>
script
export default {
name: 'WbTable',
props: {
// 服务端列表数据接口名称
url: {
type: String,
required: true
},
// 服务端列表数据接口请求参数
params: {
type: Object,
required: true
},
height: {
type: [String, Number],
default () {
return 0
}
}
},
data () {
return {
tableData: [],
loading: false,
total: 0,
isOver: false,
isError: false,
noMore: false
}
},
created () {
this.limit = this.params.limit ? this.params.limit : 8
this.offset = this.params.offset ? this.params.offset : 0
// 取设置的高度,否则按最小高度计算
this.tableHeight = this.height ? this.height : this.limit * 45 + 80
this.append(this.params)
},
methods: {
// 列表新增
async append (params) {
this.loading = true
this.$http[this.url]({
...params,
offset: this.offset,
limit: this.limit
})
.then(result => {
if (!result.data) {
this.noMore = true
return
}
this.tableData = [
...this.tableData,
...result.data.rows
]
this.total = result.data.total || 0
console.log(this.tableData, this.total)
// 判断是否需要加载下一页
if (this.tableData.length >= this.total) {
this.isOver = true
}
})
// eslint-disable-next-line handle-callback-err
.catch(error => {
this.isError = true
})
.finally(() => {
this.loading = false
})
},
reset () {
debugger
this.offset = 0
this.tableData = []
this.total = 0
this.isOver = false
this.isError = false
this.noMore = false
// api动态加载完 开始重新请求数据
this.$nextTick(() => {
this.append(this.params)
})
},
nextPage (event) {
if (!this.isOver) {
this.offset = this.offset + this.limit
this.$nextTick(() => {
this.append(this.params)
})
}
}
}
}
style
<style lang="scss" scoped>
.table-append {
text-align: center;
padding: 10px;
}
.ending {
line-height: 24px;
}
.next {
/*鼠标 手形状态*/
cursor:pointer;
&:focus,&:hover{
color:#409EFF;
border-color:#c6e2ff;
background-color:#ecf5ff
}
&:active{
color:#3a8ee6;
border-color:#3a8ee6;
outline:0
}
&::-moz-focus-inner{
border:0
}
}
.arrow {
/* width: 20px;
height: 20px;
position: absolute;
top: 0px;
right: 50%;
margin-left: -11px;
border: 3px solid transparent;
border-bottom: 3px solid #000;
border-right: 3px solid #000;
z-index: 99;
opacity: .8;*/
-webkit-transform: rotate(0deg);
-webkit-animation: arrow 1.5s infinite ease-in-out;
}
@-webkit-keyframes arrow {
0% {
opacity:0;
-webkit-transform:translate(0, -5px) rotate(0deg)
}
50% {
opacity:1;
-webkit-transform:translate(0, -0px) rotate(0deg)
}
100% {
opacity:0;
-webkit-transform:translate(0, 5px) rotate(0deg)
}
}
</style>
<style lang="scss">
.el-table__body-wrapper::-webkit-scrollbar{
width: 1px;
}
.el-table__body-wrapper::-webkit-scrollbar-thumb{
border-radius: 1px;
height: 20px;
background: rgba(58, 142, 230, 0.51);
}
.el-table__body-wrapper::-webkit-scrollbar-track{
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
border-radius: 1px;
background: rgba(0, 0, 0, 0);
}
</style>