javascript
<script>
import { ref, getCurrentInstance } from '@vue/composition-api'
import { useInfiniteScroll } from '@vueuse/core'
import { PullRefresh } from 'vant'
import styled from 'vue-styled-components'
const StyledContainer = styled('div', { customStyle: {} })`
overflow:auto;
.no-more .el-divider__text{
background-color: #F2F3F5;
}
.loading-more .el-loading-spinner{
color:#3C77FE !important;
}
.data-list-empty{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
font-size: 12px;
color: #b2b2b2;
text-align: center;
.data-list-empty_img{
width: 90px;
height: 90px;
margin-bottom: 20px;
background: url(${feConfig.DEFAULT_DATA_EMPTY_IMG}) 50% no-repeat;
background-size: cover;
}
>span{
font-size: 13px;
font-weight: 400;
color: #BAC1CC;
line-height: 19px;
}
}
${props => props.customStyle || ''}
`
export default {
name: 'InfiniteScroll',
props: {
isDeleteMode: Boolean,
enableInfiniteScroll: {
type: Boolean,
default: true,
},
enablePullRefresh: Boolean,
load: Function,
pageSize: {
type: Number,
default: 10,
},
hideLoading: Boolean,
},
data () {
return {
}
},
setup (props, context) {
const dataContainer = ref(null)
const dataList = ref([])
const currentPage = ref(1)
const noMore = ref(false)
const pullRefreshLoading = ref(false)
const loading = ref(false)
const loadMoreLoading = ref(false)
const { proxy } = getCurrentInstance()
const getTableData = async (option = {}) => {
if (proxy._isDestroyed) {
return
}
// 获取数据
let start = new Date().getTime()
if (!option.loadMore) {
if (!props.hideLoading && !pullRefreshLoading.value) { // 下拉刷新
loading.value = true
}
dataList.value = []
currentPage.value = 1
noMore.value = false
} else {
loadMoreLoading.value = true
}
let ret = await props.load(currentPage.value, props.pageSize)
let diff = (new Date().getTime() - start)
if (loading.value) {
if (diff < 200) {
setTimeout(() => {
loading.value = false
}, 200)
} else {
loading.value = false
}
}
pullRefreshLoading.value = false
loadMoreLoading.value = false
if (ret) {
pushNewData(ret, option.loadMore)
}
}
//
const pushNewData = (newData, loadMore) => {
if (newData.length < props.pageSize) {
noMore.value = true
}
dataList.value.push(...newData)
}
const manualLoadMore = () => {
if (loading.value || loadMoreLoading.value) {
return
}
currentPage.value++
getTableData({ loadMore: true })
}
if (props.enableInfiniteScroll) {
useInfiniteScroll(
dataContainer,
() => {
if (noMore.value || loading.value || loadMoreLoading.value) {
return
}
currentPage.value++
getTableData({ loadMore: true })
},
{ distance: 150 },
)
}
return {
currentPage,
dataList,
dataContainer,
noMore,
loading,
getTableData,
manualLoadMore,
pushNewData,
loadMoreLoading,
pullRefreshLoading,
}
},
created () {
this.init()
},
activated () {
if (this.scrollTop) {
this.$el.scrollTop = this.scrollTop
}
},
methods: {
init () {
this.getTableData()
},
getCustomStyle () {
return ''
},
getDataContent () {
return this.dataList.map((data, index) => {
return <div>{index}</div>
})
},
getLoadMoreContent () {
return (
<div style="text-align:center;">
<el-button type="text" on-click={this.manualLoadMore}>
加载更多
</el-button>
</div>
)
},
getLoadMoreLoadingContent () {
return (
<p
style="margin-top:30px;"
class="loading-more"
v-loading={this.loadMoreLoading}
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"/>
)
},
getEmptyContent () {
return (
<div class="data-list-empty">
<div class="data-list-empty_img"/>
<span>暂无数据</span>
</div>
)
},
getNoMoreContent () {
return (
<div class="el-divider el-divider--horizontal no-more">
<div class="el-divider__text is-center">我是有底线的</div>
</div>
)
},
getSkeleton () {
return (
<el-skeleton animated loading={true} rows={6} />
)
},
getDataContainerEl () {
let dataContainer = this.$refs.dataContainer
if (dataContainer) {
return dataContainer.$el
}
return null
},
},
render () {
let { currentPage, noMore, loadMoreLoading, loading, dataList, enablePullRefresh } = this
const dataContainer = (
<StyledContainer
ref="dataContainer"
class={['data-container', !loading && currentPage === 1 && dataList.length === 0 ? 'is-empty' : '']}
customStyle={this.getCustomStyle()}>
{!loading ? this.getDataContent() : null}
{!loading && currentPage === 1 && dataList.length === 0 ? this.getEmptyContent() : null}
{!loadMoreLoading && !loading && !noMore && !this.enableInfiniteScroll ? this.getLoadMoreContent() : null}
{noMore && currentPage > 1 ? this.getNoMoreContent() : null}
{loadMoreLoading ? this.getLoadMoreLoadingContent() : null}
{!loadMoreLoading && loading ? this.getSkeleton() : null}
</StyledContainer>
)
if (!enablePullRefresh) {
return dataContainer
}
return (
<PullRefresh
v-model={this.pullRefreshLoading}
on-refresh={this.getTableData}
class="pull-refresh-container">
{dataContainer}
</PullRefresh>
)
},
}
</script>
应用:
继承该组件,复写渲染方法。