Element-plus中v-infinite-scroll指令自动加载问题

205 阅读2分钟

主要问题:使用该指令时,初次加载数据是会根据剩余空间来判断当前是否需滚动加载数据,但是在更新搜索数据后,就并不会根据剩余高度来加载数据,仅仅只是第一页

演示地址:element-playground平台

在上述的演示中,第一次进入是可以进行滚动加载,当点击重置按钮后,就无法进行滚动

问题分析:在element-plus的源码当中发现,当数据已经超出区域后,就销毁了区域没有填满的observer。点击重置后,updated时期只有当observer存在时才会检查区域是否填满

具体代码:

if (immediate) {
   // 通过MutationObserver监听元素变化
  const observer = new MutationObserver(
     throttle(checkFull.bind(null, el, cb), CHECK_INTERVAL)
   )
   el[SCOPE].observer = observer
   observer.observe(el, { childList: true, subtree: true })
   checkFull(el, cb)
 }
function checkFull(el: InfiniteScrollEl, cb: InfiniteScrollCallback) {
 const { containerEl, instance } = el[SCOPE]
 const { disabled } = getScrollOptions(el, instance)

 if (disabled || containerEl.clientHeight === 0) return

 if (containerEl.scrollHeight <= containerEl.clientHeight) {
   cb.call(instance)
 } else {
   destroyObserver(el) //销毁监听器
 }
}

async updated(el) {
   if (!el[SCOPE]) {
     await nextTick()
   } else {
     const { containerEl, cb, observer } = el[SCOPE] // observer被销毁就不会执行下面的checkFull
     if (containerEl.clientHeight && observer) {
       checkFull(el, cb)
     }
   }
 },

解决方法:禁用infinite-scroll-immediate的属性,增加是否需要数据加载的判断逻辑

async function getTableData() {
  // 接口请求获取数据

  const container = document.querySelector(`.${ns.b('content-table')}`)
  const content = document.querySelector(`.${ns.be('content-table', 'body')}`)
  if (container && content) {
    containerHeight.value = container.clientHeight
    contentHeight.value = content.scrollHeight
    // 检查是否需要继续加载
    checkNeedMore()
  }
}

function checkNeedMore() {
  // 如果内容高度小于容器高度,且还有更多数据可以加载,则继续加载
  if (contentHeight.value < (containerHeight.value - 60)
      && (!tableDataCount.value || tableData.value.length < tableDataCount.value))
    scrollNextPage()
}

contribution:既然是updated当中出现问题,就对源码进行修改。在updated当中根据是否设置了immediate,存在且当observer被销毁的时候就重新创建observer进行监听。

已提交贡献,待review

async updated(el) {
    if (!el[SCOPE]) {
      await nextTick()
    } else {
      const { containerEl, cb, instance } = el[SCOPE]
      const { immediate } = getScrollOptions(el, instance)

      if (containerEl.clientHeight && immediate) {
        if (!el[SCOPE].observer) {
          const observer = new MutationObserver(
            throttle(checkFull.bind(null, el, cb), CHECK_INTERVAL)
          )
          el[SCOPE].observer = observer
          observer.observe(el, { childList: true, subtree: true })
        }
        checkFull(el, cb)
      }
    }
  },