无限滚动组件封装(vue+vant)

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>

应用:

继承该组件,复写渲染方法。

相关推荐
m0_564914922 分钟前
EDGE浏览器如何在新标签页打开收藏?EDGE浏览器如何打开书签不覆盖原网页?如何默认在新建标签页打开收藏夹书签?
前端·edge
司铭鸿17 分钟前
图论中的协同寻径:如何找到最小带权子图实现双源共达?
linux·前端·数据结构·数据库·算法·图论
风宇啸天39 分钟前
令牌桶按用户维度限流
前端
safestar201241 分钟前
React 19 深度解析:从并发模式到数据获取的架构革命
前端·javascript·react.js
越努力越幸运5081 小时前
npm常见问题解决
前端·npm·node.js
Wild~~1 小时前
electron-vite
前端·javascript·electron
by__csdn1 小时前
Electron+Vite:实现electron + vue3 + ts + pinia + vite高效跨平台开发指南
前端·javascript·vue.js·typescript·electron·node.js·vue
国服第二切图仔1 小时前
Electron 鸿蒙pc开发环境搭建完整保姆级教程(window)
javascript·electron·harmonyos
马达加斯加D1 小时前
C# --- 如何写UT
前端·c#·log4j
yqcoder1 小时前
在 scss 中,&>div 作用
前端·css·scss