Appearance
infiniteScroll 无限滚动指令
当滚动到容器底部时自动触发加载函数,实现无限滚动列表效果。
安装与引入
按需导入(推荐)
ts
import { VInfiniteScroll } from '@cuixingjian/cui-utils'全局注册
ts
import { createApp } from 'vue'
import { VInfiniteScroll } from '@cuixingjian/cui-utils'
const app = createApp(App)
app.directive('infinite-scroll', VInfiniteScroll)
app.mount('#app')局部注册
vue
<script setup lang="ts">
import { VInfiniteScroll as vInfiniteScroll } from '@cuixingjian/cui-utils'
</script>
<template>
<div v-infinite-scroll="loadMore" style="overflow: auto; height: 400px;">
<div v-for="item in list" :key="item">{{ item }}</div>
</div>
</template>效果演示
基本用法
滚动到底部自动加载更多数据。
使用代码
基本用法:
vue
<script setup lang="ts">
import { VInfiniteScroll as vInfiniteScroll } from '@cuixingjian/cui-utils'
const loadMore = () => {
// 加载更多数据
console.log('加载更多')
}
</script>
<template>
<div v-infinite-scroll="loadMore" style="overflow: auto; height: 400px;">
<!-- 列表内容 -->
</div>
</template>配置选项:
vue
<script setup lang="ts">
import { ref } from 'vue'
import { VInfiniteScroll as vInfiniteScroll } from '@cuixingjian/cui-utils'
const loading = ref(false)
const loadMore = () => {
loading.value = true
// 加载数据...
setTimeout(() => {
loading.value = false
}, 1000)
}
</script>
<template>
<div
v-infinite-scroll="loadMore"
:infinite-scroll-disabled="loading"
:infinite-scroll-distance="50"
:infinite-scroll-delay="300"
style="overflow: auto; height: 400px;"
>
<!-- 列表内容 -->
</div>
</template>使用对象配置:
vue
<script setup lang="ts">
const options = {
disabled: false,
distance: 100,
immediate: true,
delay: 200
}
const loadMore = () => {
console.log('加载更多')
}
</script>
<template>
<div v-infinite-scroll="{ ...options, callback: loadMore }">
<!-- 列表内容 -->
</div>
</template>API 说明
指令值类型
| 类型 | 说明 | 示例 |
|---|---|---|
Function | 滚动到底部时触发的回调函数 | v-infinite-scroll="loadMore" |
Object | 传入配置对象(需包含 callback) | v-infinite-scroll="{ disabled: false }" |
配置选项 (InfiniteScrollOptions)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| disabled | boolean | false | 是否禁用指令 |
| distance | number | 0 | 触发加载的距离阈值(像素) |
| immediate | boolean | true | 是否立即检查(内容不足一屏时) |
| delay | number | 200 | 防抖延迟时间(毫秒) |
指令修饰符
通过 HTML 属性传递配置:
| 属性 | 类型 | 说明 |
|---|---|---|
infinite-scroll-disabled | boolean | 是否禁用 |
infinite-scroll-distance | number | 距离阈值 |
infinite-scroll-immediate | boolean | 是否立即检查 |
infinite-scroll-delay | number | 延迟时间 |
使用场景
- 新闻列表 - 用户滚动浏览新闻时,自动加载下一页内容,提供流畅的阅读体验
- 图片瀑布流 - 在图片展示页面,滚动到底部时自动加载更多图片,适合相册、作品集等场景
- 聊天记录 - 向上滚动查看历史消息时,自动加载更早的聊天记录
- 商品列表 - 电商网站的商品浏览页面,滚动加载更多商品
- 社交动态 - 类似微博、朋友圈的信息流,持续加载新内容
- 搜索结果 - 搜索结果页面的分页加载,提升用户体验
注意事项
容器要求
- 必须设置
overflow: auto或overflow-y: auto - 必须设置固定高度
- 容器必须是可滚动的
防止重复加载
使用 disabled 选项在加载时禁用指令:
vue
<script setup lang="ts">
const loading = ref(false)
const disabled = computed(() => loading.value || noMore.value)
</script>
<template>
<div
v-infinite-scroll="load"
:infinite-scroll-disabled="disabled"
>
<!-- 内容 -->
</div>
</template>立即检查
当 immediate: true 时,指令会在挂载后立即检查一次,如果内容不足一屏会自动触发加载。
性能优化
- 使用
delay选项设置防抖延迟,避免频繁触发 - 使用
distance选项提前触发加载,提升用户体验 - 监听内容变化,自动重新检查(使用 ResizeObserver)
最佳实践
vue
<script setup lang="ts">
import { ref, computed } from 'vue'
const list = ref([])
const loading = ref(false)
const noMore = ref(false)
// 组合禁用条件
const disabled = computed(() => loading.value || noMore.value)
const loadMore = async () => {
if (disabled.value) return
loading.value = true
try {
const data = await fetchData()
if (data.length === 0) {
noMore.value = true
} else {
list.value.push(...data)
}
} catch (error) {
console.error('加载失败', error)
} finally {
loading.value = false
}
}
</script>
<template>
<div
v-infinite-scroll="loadMore"
:infinite-scroll-disabled="disabled"
:infinite-scroll-distance="50"
:infinite-scroll-delay="200"
style="height: 500px; overflow: auto;"
>
<div v-for="item in list" :key="item.id">
{{ item.name }}
</div>
<div v-if="loading">加载中...</div>
<div v-if="noMore">没有更多了</div>
</div>
</template>源码展示
展开查看完整源码
ts
import type { Directive } from 'vue'
import { withInstallDirective } from '../install'
export interface InfiniteScrollOptions {
disabled?: boolean
distance?: number
immediate?: boolean
delay?: number
}
type BindingValue = (() => void) | InfiniteScrollOptions
// 详见 packages/utils/directives/infiniteScroll.ts
export const VInfiniteScroll = withInstallDirective(infiniteScroll, 'infinite-scroll')