无限滚动组件封装(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>

应用:

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

相关推荐
傻虎贼头贼脑3 分钟前
day21JS-npm中的部分插件使用方法
前端·npm·node.js
小胖伦的夕阳粉14 分钟前
js 获取树节点上某节点的最底层叶子节点数据
开发语言·javascript·ecmascript
low神15 分钟前
前端在网络安全攻击问题上能做什么?
前端·安全·web安全
@听风吟30 分钟前
力扣之182.查找重复的电子邮箱
大数据·javascript·数据库·sql·leetcode
码力码力我爱你1 小时前
QT + WebAssembly + Vue环境搭建
vue.js·vue·wasm·webassembly·emscripten
qbbmnnnnnn1 小时前
【CSS Tricks】如何做一个粒子效果的logo
前端·css
唐家小妹1 小时前
【flex-grow】计算 flex弹性盒子的子元素的宽度大小
前端·javascript·css·html
涔溪1 小时前
uni-app环境搭建
前端·uni-app
安冬的码畜日常1 小时前
【CSS in Depth 2 精译_032】5.4 Grid 网格布局的显示网格与隐式网格(上)
前端·css·css3·html5·网格布局·grid布局·css网格布局
洛千陨1 小时前
element-plus弹窗内分页表格保留勾选项
前端·javascript·vue.js