說明
自用
一、自定義指令實現
參考:
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 滾動加載:http://www.lxweimin.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>