滚动懒加载升级版:添加滚动回收策略

在之前的1.0版本的基础上,添加滚动回收策略,保持页面只保留固定数量的数据,优化渲染

否则一直往数组里push内容,当数组长度过大,可能页面会崩溃(本需求是日志列表,由于日志数据可能会非常庞大,所以添加回收策略,如果列表数据不会很大,可以不用回收)

1.0版本代码如下:

vue3——利用自定义指令实现下拉框分页懒加载_vue3 el-select懒加载-CSDN博客

关于clientHeight、scrollTop和scrollHeight的关系

因此,可以利用这个关系,写出滚动条滚动到最上面和最下面的距离,

最上面:DOM.scrollTop + DOM.clientHeight == DOM.scrollHeight

最下面:DOM.scrollTop==0

但是为了更流畅的用户体验,可以让滚动条即将触顶或即将触底的时候就触发回调,可以加个阈值。


在该实践中,一页数据为10条,保持页面的数据恒定在50条(5页数据),滚动条向下滑动触底时,若大于5页,在请求第六页的同时,回收第一页的内容;反之,滚动条向上滑动触顶时,重新请求被回收的数据,同时,回收数组最末尾的一页数据,以此类推,保持整个页面的DOM只渲染小于50条数据。

自定义指令代码如下:

(ps:相比1.0版本加了阈值,加了即将触顶的判断,还加了节流,防止多次重复触发)

//自定义指令:实现下拉框下拉到末尾时,加载下一页的内容
// 使用时传两个参数,一个是下拉框的class,一个是下拉框滚动到末尾时触发的函数,比如:
// v-el-select-loadmore="{
//   selector: '.myOption .el-select-dropdown .el-select-dropdown__wrap',
//   loadFunction: loadMore
// }"
import { scrollType } from '@/views/AdminConsole/logManage/tenantLog/tenantLogType'
export default {
  mounted(el, binding) {
    //解构传来的值
    const {
      value: { selector, loadFunction }
    } = binding
    const SELECTWRAP_DOM = document.querySelector(selector)
    //滚动事件添加节流,性能优化
    let topScrollTimeout = null
    let bottomScrollTimeout = null
    if (SELECTWRAP_DOM) {
      const scrollHandler = () => {
        //清空定时器
        if (topScrollTimeout) {
          clearTimeout(topScrollTimeout)
        }
        if (bottomScrollTimeout) {
          clearTimeout(bottomScrollTimeout)
        }
        bottomScrollTimeout = setTimeout(() => {
          const condition = SELECTWRAP_DOM.scrollTop + SELECTWRAP_DOM.clientHeight >= SELECTWRAP_DOM.scrollHeight - 2
          //滚动条滚到最下面
          if (condition) {
            loadFunction(scrollType.bottom)
          }
        }, 300)
        topScrollTimeout = setTimeout(() => {
          const scrollTop = SELECTWRAP_DOM.scrollTop
          const threshold = 2
          //滚动到最上面
          if (scrollTop <= threshold) {
            loadFunction(scrollType.top)
          }
        }, 300)
      }
      //赋值,为了方便销毁
      el.dom = SELECTWRAP_DOM
      el.event = scrollHandler
      //监听滚动事件
      SELECTWRAP_DOM.addEventListener('scroll', scrollHandler)
    }
  },
  beforeUnmount(el) {
    if (el.dom && el.event) {
      el.dom.removeEventListener('scroll', el.event)
    }
  }
}

index.vue 

/**
 * 滚动条触底的逻辑
 */
async function scrollToBottom() {
  //滚动到最下面
  startPage += 1
  endPage += 1
  //发请求,获得接口数据
  bottomLoading.value = true
  try {
    await getLogListWrap(copySearchObj.value, endPage)
  } catch (err) {
    proxy.$errorHandle(err)
  }
  tableData.push(...itemList)
  //删除原数组前10项
  tableData.splice(0, 10)
}
/**
 * 滚动条触顶的逻辑
 */
async function scrollToTop() {
  startPage -= 1
  endPage -= 1
  //发请求,获得接口数据
  topLoading.value = true
  try {
    await getLogListWrap(copySearchObj.value, startPage)
  } catch (err) {
    proxy.$errorHandle(err)
  }
  tableData.unshift(...itemList)
  //如果是最后一页,删掉原数组最后的项数
  if (endPage == totalPage - 1) {
    let lastItem = totalCount % 10
    tableData.splice(tableData.length - lastItem, lastItem)
  } else {
    //删掉原数组后10项
    tableData.splice(tableData.length - 10, 10)
  }
}
/**
 * 性能优化:只保留50条数据,tableData在尾部增加数据的时候,删除头部的部分数据,反之也是
 * @param flag 判断是滚动条是触底还是触顶
 */
async function loadMore(flag: String) {
  const { clientHeight, scrollHeight } = timelineRef.value
  let isBottom = flag === scrollType.bottom
  if (isBottom) {
    if (totalCount <= 50 || endPage == totalPage) {
      return
    }
    scrollToBottom()
    //让滚动条向上滚一些距离,方便下次继续触发
    nextTick(() => {
      timelineRef.value.scrollTo(0, scrollHeight - clientHeight - 10)
    })
  } else {
    //滚动到最上面
    if (totalCount <= 50 || startPage == 1) {
      return
    }
    scrollToTop()
    //让滚动条向下滚一些距离,方便下次继续触发
    nextTick(() => {
      timelineRef.value.scrollTo(0, 20)
    })
  }
}

ps:滚动条触顶或者触底时,必须要用scrollTo方法让滚动条向下或者向上走一点距离,否则滚动条的位置会保持不变,就不会触发下一次回调。因为回调触发的条件是触顶或者触底,而不是一直让滚动条呆在顶部或者底部,必须有接触的行为。 

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值