Skip to content

@sheng/prefer-load-more-trigger ​

提示疑似无限滚动场景不要手写 IntersectionObserver,优先使用 useLoadMoreTrigger。

所属 config ​

  • load-more-trigger:无限滚动触底触发器复用约定。

为什么需要 ​

无限滚动不只是观察底部 sentinel。虚拟列表会改写内容高度和 DOM 节点,短列表首屏也可能在数据回来后仍然需要补偿重检。只手写 useIntersectionObserver,很容易漏掉 scroll fallback、数据变化后的 recheck 和 loading / hasMore 的时序。

会提示 ​

vue
<script setup lang="ts">
import { useIntersectionObserver } from '@vueuse/core'

const loadMoreSentinelElement = shallowRef<HTMLElement | null>(null)
const hasMore = computed(() => nextIndex.value > 0)

function loadMoreActiveTab() {}

useIntersectionObserver(loadMoreSentinelElement, ([entry]) => {
  if (entry?.isIntersecting && hasMore.value) loadMoreActiveTab()
})
</script>

推荐写法 ​

ts
useLoadMoreTrigger({
  canLoadMore: computed(() => hasMore.value && !loading.value),
  loadMore: loadMoreActiveTab,
  scrollElement,
  sentinelElement: loadMoreSentinelElement,
  recheckSources: [items, activeTab],
})

适用边界 ​

优先在已经采用 load-more-trigger 约定的项目里开启。历史代码较多时,先按目录或文件范围试跑,确认误报成本可以接受。

规则判断比较保守:源码里同时出现 sentinel 命名,以及 loadMore、hasMore、nextIndex 这类加载更多信号时,才会提示 @vueuse/core 里的 useIntersectionObserver。普通曝光、懒加载和动画触发场景不会因为用了 observer 就被拦。

相关阅读 ​

这条规则对应中文文章 把无限滚动触底触发器抽成 composable:虚拟列表、哨兵和滚动兜底。文章里的核心结论是:useLoadMoreTrigger 只负责触发时机,分页请求、cursor、错误态和 tab 切换仍归列表 owner;Lint 只提醒疑似新手写的 load-more observer。

接入方式 ​

@sheng/eslint-plugin 的内置 config 会以 warn 开启这条规则。需要单独配置时,可以这样写:

js
import sheng from '@sheng/eslint-plugin'

export default [
  {
    plugins: {
      '@sheng': sheng,
    },
    rules: {
      '@sheng/prefer-load-more-trigger': 'warn',
    },
  },
]

选项 ​

这条规则支持 options,具体 schema 以规则实现和测试用例为准。补充或调整选项时,同步更新本页示例。

维护入口 ​

  • 规则源码:src/rules/prefer-load-more-trigger/index.mjs
  • 规则短说明:src/rules/prefer-load-more-trigger/README.md
  • 测试用例:tests/unit/architecture/

基于 MIT 协议发布。