列表页图片多、数据量大时,懒加载能明显减少首屏流量与白屏时间。本文提供两个互补方案:图片懒加载指令 v-lazy 用 IntersectionObserver 判定元素是否进入视口;滚动加载 Hook 在页面快到底时自动调用下一页接口。
图片懒加载指令
// src/directives/lazy.js
const lazy = {
mounted(el, binding) {
// 真实地址暂存到 dataset,避免直接加载
el.dataset.src = binding.value;
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
el.src = el.dataset.src;
observer.unobserve(el); // 加载后停止观察
}
});
});
observer.observe(el);
}
};
export default lazy;
滚动加载 Hook
// src/hooks/useInfiniteScroll.js
import { onMounted, onUnmounted, ref } from "vue";
export function useInfiniteScroll(loadFn) {
const loading = ref(false);
const finished = ref(false);
const onScroll = async () => {
const doc = document.documentElement;
const distance = doc.scrollHeight - doc.scrollTop - doc.clientHeight;
if (distance > 200 || loading.value || finished.value) return;
loading.value = true;
try {
const hasMore = await loadFn();
if (!hasMore) finished.value = true;
} finally {
loading.value = false;
}
};
onMounted(() => window.addEventListener("scroll", onScroll));
onUnmounted(() => window.removeEventListener("scroll", onScroll));
return { loading, finished };
}
页面使用
图片元素写 <img v-lazy="item.cover" />,列表页 onMounted 调一次 loadFn 拉第一页,后续触底自动续页;loadFn 返回布尔值表示是否还有下一页。
注意
- 容器内滚动而不是整页滚动时,需把监听目标换成对应滚动容器的 DOM;
- IntersectionObserver 支持度较广,低版本浏览器可降级为监听 scroll 加 getBoundingClientRect;
- 移动端注意 passive 事件与滚动性能,避免加载卡顿。
小结
懒加载与无限滚动是长列表页性能优化的一对组合拳,抽成指令与 Hook 后业务页面只需配置数据来源即可。
评论(0)
暂无评论,快来抢沙发吧~