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

应用:

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

相关推荐
cy玩具21 分钟前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
清灵xmf1 小时前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据1 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_390161771 小时前
防抖函数--应用场景及示例
前端·javascript
334554322 小时前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test2 小时前
js下载excel示例demo
前端·javascript·excel
Yaml42 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事2 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶2 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json