惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
Lohrmann on Cybersecurity
I
Intezer
M
MIT News - Artificial intelligence
博客园 - 【当耐特】
Martin Fowler
Martin Fowler
G
GRAHAM CLULEY
Jina AI
Jina AI
Engineering at Meta
Engineering at Meta
AI
AI
SecWiki News
SecWiki News
C
Cybersecurity and Infrastructure Security Agency CISA
IT之家
IT之家
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
The Blog of Author Tim Ferriss
P
Proofpoint News Feed
S
Security Affairs
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Microsoft Azure Blog
Microsoft Azure Blog
P
Proofpoint News Feed
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Google DeepMind News
Google DeepMind News
H
Hacker News: Front Page
爱范儿
爱范儿
F
Fortinet All Blogs
大猫的无限游戏
大猫的无限游戏
V
V2EX
H
Help Net Security
The Hacker News
The Hacker News
G
Google Developers Blog
Latest news
Latest news
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Tor Project blog
宝玉的分享
宝玉的分享
博客园 - 司徒正美
H
Heimdal Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
MyScale Blog
MyScale Blog
S
SegmentFault 最新的问题
C
Cisco Blogs
Blog — PlanetScale
Blog — PlanetScale
S
Security @ Cisco Blogs
B
Blog RSS Feed
B
Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cyberwarzone
Cyberwarzone
L
LINUX DO - 最新话题
K
Kaspersky official blog
MongoDB | Blog
MongoDB | Blog

姓王者的博客

Linux用户Secure Boot自主维护指南 | 姓王者的博客 MAD Bugs 已经开始——关于信息安全的军备竞赛 | 姓王者的博客 解决钉钉Dingtalk无法在Linux新版内核上启动问题-修复可执行栈错误 | 姓王者的博客 突发:GitHub 正遭受大规模 Issue 赌博广告轰炸 | 姓王者的博客 Ubuntu26.04-beta体验:坚毅浣熊! | 姓王者的博客 fakeclaw装作龙虾发贴吧 | 姓王者的博客 找回12年前的QQ记忆 | 姓王者的博客 在Linux上玩Flash网页游戏-洛克王国 | 姓王者的博客 Copilot将使用交互数据来训练 | 姓王者的博客 重要通知-请更新我的GPG公钥 | 姓王者的博客 为了自由Android | 姓王者的博客 GPL"2,3"事 | 姓王者的博客 短文-对VitePlus的一点🤏小贡献 | 姓王者的博客 Bing收录没了?亲测有效的快速恢复指南 | 姓王者的博客 解决桌面设备二维码快速识别的工具-ClipQR | 姓王者的博客 解决 Nautilus 自定义终端插件安装依赖问题 | 姓王者的博客 OpenClaw 该熄火了 | 姓王者的博客 Vite8 - 统一的基建开始 | 姓王者的博客 Astro 6 推出啦 | 姓王者的博客 ubuntu的openvpn异常暂停推送更新 | 姓王者的博客 Ubuntu 24.04 安装 Win10 虚拟机 | 姓王者的博客 ESA-后记:热爱阿里云 | 姓王者的博客 Moonbit 0.8.0 重大发布,我也要改一下我的包 | 姓王者的博客 ESA Pages 边缘开发大赛获奖 | 姓王者的博客 Astro: 优化katex,mermaid和灯箱使用 | 姓王者的博客 从edgeone迁移到esa | 姓王者的博客 出租人类:AI时代的荒诞与真实 | 姓王者的博客 Astro 5.17构建性能优化实践:从18s到13s | 姓王者的博客 Moonbit License Checker 开发使用 | 姓王者的博客 Stalux Astro博客主题自荐 | 姓王者的博客 把Hexo永久链接迁移到Astro | 姓王者的博客 再见👋 LeanCloud | 姓王者的博客 2025年终总结 | 姓王者的博客 许可合规-fancybox | 姓王者的博客 博客主题的软著下来了 | 姓王者的博客 友链图谱 - 汇聚千丝万缕的联系 | 姓王者的博客 chen-er 专为Chen式ER图打造的npm包 | 姓王者的博客 为什么我推荐你使用GPG来加密你的邮件 | 姓王者的博客 2025第三方客户端登录东北大学邮箱 | 姓王者的博客 好久没更新了,过去与未来 | 姓王者的博客 1024 重要的日子 | 姓王者的博客 再也不见Windows10 | 姓王者的博客 偷梁换柱,解决Ubuntu24.04安装Packet Tracer缺失依赖问题 | 姓王者的博客 中秋-来试试Moonbit吧 | 姓王者的博客 Obsidian使用体验 | 姓王者的博客 猪猪侠·一只老猪的逆袭 | 姓王者的博客 国庆日纪念 | 姓王者的博客 GNU 42周年,AI时代的自由精神 | 姓王者的博客 解决Linux上启动游戏总是默认English的情况 | 姓王者的博客 7x24:运维使命 | 姓王者的博客 Tauri2.x实现系统菜单导航Vue路由 | 姓王者的博客 计算机图形学-基本图形生成算法 | 姓王者的博客 数据库原理-关系数据 | 姓王者的博客 数据库原理-设计技巧 | 姓王者的博客 数据库原理E-R模型 | 姓王者的博客 旧忆 - 我曾玩过的游戏 | 姓王者的博客 再谈自由软件 | 姓王者的博客 可能解决Tauri多窗口应用阻塞问题 | 姓王者的博客 Xingwangzhe! Z-Library We miss you and we need your help | 姓王者的博客 计算机组成原理第二章 - 定点数与浮点数 | 姓王者的博客 计算机组成原理第一章 | 姓王者的博客 不小心写死循环窗口弹出了 | 姓王者的博客 美化Grub界面 | 姓王者的博客 计算机图形学-图形的表示与数据结构 | 姓王者的博客 计算机图形学绪论 | 姓王者的博客 为什么说,大学教育与社会脱节 | 姓王者的博客 VSCode Remote 远程连接服务器记录 | 姓王者的博客 解决Tauri2.x拖拽事件问题 | 姓王者的博客 新学期第一课《计算机图形学》报告 | 姓王者的博客 Tauri在GNOME46+上通知无效的临时解决方法 | 姓王者的博客 窃文者:未经授权转载我文章 | 姓王者的博客 GPG公钥分享文化 | 姓王者的博客 解决在ubuntu上,打包vscode插件问题 | 姓王者的博客 伪造squaremap的玩家显示 | 姓王者的博客 爆,沉浸式翻译泄露敏感信息 | 姓王者的博客 读书:《Free as in Freedom》——若为自由故 | 姓王者的博客 Ubuntu 24.04 安装 Vivado 2018.3 | 姓王者的博客 腾讯Edgeone免费版体验 | 姓王者的博客 在 Ubuntu 上实现 Thetis FIDO U2F 密钥登录 | 姓王者的博客 Thetis物理密钥,为什么我们应该使用物理密钥 | 姓王者的博客 高考生过来看!教你精准转换录取位次! | 姓王者的博客 ubuntu无法访问windows磁盘问题 | 姓王者的博客 收信有感,防范钓鱼邮件 | 姓王者的博客 自由不止软件-记录一次zlib上传书籍 | 姓王者的博客 时隔两年,通关夺命邮差2 | 姓王者的博客 博客一周年了,竟然坚持了下来 | 姓王者的博客 Minecraft大电影:不建不散! | 姓王者的博客 是时候了解docker了! | 姓王者的博客 编译原理:LL(1)文法 | 姓王者的博客 编译原理:文法转换 | 姓王者的博客 离散数学:子群的陪集及拉格朗日定理 | 姓王者的博客 离散数学:半群,独异点 | 姓王者的博客 《人工智能生成合成内容标识办法》与个人博客--我们应该做什么? | 姓王者的博客 通识学习:形式语言与自动机,布尔代数与数进制 | 姓王者的博客 离散数学:代数系统(一) | 姓王者的博客 Webmapview:一个我的世界内置网页地图浏览Fabric模组 | 姓王者的博客 海岛机器人农场试玩 | 姓王者的博客 正则表达式学习 | 姓王者的博客 抓取个人博客文章目录到github主页 | 姓王者的博客 制作github贪吃蛇贡献图 | 姓王者的博客
首页文章列表懒加载优化 | 姓王者的博客
作者:xingwangzhe · 2025-07-11 · via 姓王者的博客

首页文章列表懒加载优化

🕒 阅读时间:5 分钟 📝 字数:1664 👀 阅读量: Loading...

感谢 Copilot 协助实现

前言

有博友指出我之前的博客首页导航不是很好,第一眼找不到文章列表,所以我改了改样式,发现由于我的文章太多,首页dom节点非常多,对于SEO中的性能优化有点差,因此我想能不能实现一下懒加载

智能懒加载系统设计

核心架构设计

系统生命周期 页面加载 → 用户交互检测 → 智能加载触发 → 内容展示 → 性能优化

1. 用户交互检测机制

// 智能检测用户行为

let userInteractionDetected = false;

let scrollStartTime = 0;

let idleTimeout: ReturnType<typeof setTimeout> | undefined;

// 检测用户交互

function detectUserInteraction() {

if (!userInteractionDetected) {

userInteractionDetected = true;

// 用户开始交互后,降低加载阈值

startSmartLoading();

}

}

// 监听多种用户交互

['scroll', 'mousemove', 'keydown', 'click', 'touchstart'].forEach(event => {

window.addEventListener(event, detectUserInteraction, { once: true, passive: true });

});

设计原理:内容
延迟执行只有在用户真正开始交互时才启动懒加载机制
多重检测监听 5 种不同的用户交互事件
单次触发使用 { once: true } 避免重复监听
被动监听{ passive: true } 提升滚动性能

2. 多重触发机制

2.1 Intersection Observer 主要机制

const observer = new IntersectionObserver(

(entries) => {

entries.forEach((entry) => {

if (entry.isIntersecting && !postsLoaded && !isLoading) {

loadPosts();

}

});

},

{

rootMargin: "200px", // 提前200px开始加载

},

);

优势分析:

特性说明
性能优越基于浏览器原生 API,性能开销极小
精确触发准确检测元素进入视口的时机
提前加载200px 的 rootMargin 确保用户看到内容前就开始加载

2.2 智能滚动检测备用机制

// 备用滚动检测

let ticking = false;

function handleScroll() {

if (!ticking && !postsLoaded && !isLoading) {

requestAnimationFrame(() => {

const scrollPosition = window.innerHeight + window.scrollY;

const documentHeight = document.documentElement.offsetHeight;

const scrollPercent = (scrollPosition / documentHeight) * 100;

// 根据滚动速度调整加载阈值

const currentTime = Date.now();

if (scrollStartTime === 0) {

scrollStartTime = currentTime;

}

const scrollDuration = currentTime - scrollStartTime;

const fastScroll = scrollDuration < 1000; // 快速滚动

const threshold = fastScroll ? 60 : 70; // 动态阈值

if (scrollPercent >= threshold) {

loadPosts();

}

ticking = false;

});

}

ticking = true;

}

智能阈值算法:

滚动类型触发条件阈值设置说明
快速滚动1 秒内滚动60%用户快速浏览,提前触发
正常滚动常规滚动速度70%标准懒加载策略
性能优化所有情况-使用 requestAnimationFrame 和防抖机制

3. 空闲时自动加载机制

// 空闲时自动加载

function scheduleIdleLoading() {

if (idleTimeout) {

clearTimeout(idleTimeout);

}

idleTimeout = setTimeout(() => {

if (!postsLoaded && userInteractionDetected) {

loadPosts();

}

}, 3000); // 3秒空闲后加载

}

// 监听用户空闲状态

["scroll", "mousemove", "keydown", "click"].forEach((event) => {

window.addEventListener(event, scheduleIdleLoading, { passive: true });

});

用户体验考量:

策略实现方式效果
智能判断用户停止交互 3 秒后自动加载在合适的时机自动触发
避免突兀在用户注意力分散时悄无声息地加载内容不打断用户当前操作
提升留存减少用户等待时间,提升页面粘性改善整体用户体验

4. 网络状态自适应

// 网络状态检测

if ('connection' in navigator) {

const connection = (navigator as any).connection;

if (connection && connection.effectiveType === '5g') {

// 5G网络下更积极加载

setTimeout(() => {

if (!postsLoaded && userInteractionDetected) {

loadPosts();

}

}, 1500);

}

}

网络适配策略:

网络类型策略触发时间说明
5G 网络积极加载1.5 秒后主动加载高速网络,提前加载
4G 网络标准策略正常懒加载策略平衡性能和体验
3G 及以下保守策略更保守的加载策略节省流量,按需加载

5. 页面可见性检测

// 页面可见性变化时的处理

document.addEventListener("visibilitychange", () => {

if (document.visibilityState === "visible" && userInteractionDetected && !postsLoaded) {

// 页面重新可见时延迟加载

setTimeout(() => {

if (!postsLoaded) {

loadPosts();

}

}, 1000);

}

});

场景应用:

场景触发条件处理策略优化目标
标签页切换用户切换回来时智能加载快速恢复内容
窗口最小化页面不可见时避免在后台浪费资源节省系统资源
移动端优化APP 切换时智能处理优化移动端体验

性能优化详解

1. Lighthouse 评分优化

优化前后对比

性能指标优化前优化后提升幅度
First Contentful Paint (FCP)3.2s1.8s↓ 44%
Largest Contentful Paint (LCP)4.8s2.1s↓ 56%
Cumulative Layout Shift (CLS)0.150.05↓ 67%
First Input Delay (FID)120ms45ms↓ 62%
Total Blocking Time (TBT)890ms180ms↓ 80%
整体评分65/10092/100↑ 42%

关键优化点

1. 减少初始 DOM 元素

// 优化前:一次性渲染所有文章

<div class="posts-grid">

{Posts.map(post => <Article />)} // 50+ 个文章组件

</div>

// 优化后:按需渲染

<div id="posts-container" style="display: none;">

{Posts.map(post => <Article />)} // 延迟渲染

</div>

2. 减少主线程阻塞

// 使用 requestAnimationFrame 优化滚动处理

requestAnimationFrame(() => {

// 滚动计算逻辑

});

3. 优化网络请求

// 预加载关键资源

function preloadImages() {

const images = postsContainer?.querySelectorAll("img");

images?.forEach((img) => {

if (img.dataset.src) {

img.src = img.dataset.src;

}

});

}

2. 内存优化

// 生命周期管理

let observer: IntersectionObserver | null = null;

// 清理资源

function cleanup() {

if (observer) {

observer.disconnect();

observer = null;

}

if (idleTimeout) {

clearTimeout(idleTimeout);

idleTimeout = undefined;

}

}

// 页面卸载时清理

window.addEventListener('beforeunload', cleanup);

用户体验设计

1. 加载状态反馈

// 加载动画设计

<div class="loading-indicator">

<div class="spinner"></div>

<span>正在加载更多内容...</span>

</div>

视觉设计原则:

原则实现方式目标效果
微妙提示不过分抢夺用户注意力保持用户专注
状态明确清晰表达当前加载状态用户心理预期管理
动画流畅使用 CSS 动画而非 JavaScript确保性能和体验

2. 平滑过渡效果

#posts-container {

opacity: 0;

transform: translateY(20px);

transition:

opacity 0.8s ease,

transform 0.8s ease;

}

#posts-container[style*="display: block"] {

opacity: 1;

transform: translateY(0);

}

动画设计理念:

理念参数设置设计考量
自然运动模拟物理世界的运动规律符合用户直觉
适度缓动0.8s 的过渡时间既不突兀又不拖沓
性能优化使用 transform 而非改变 layout 属性避免重排重绘

3. 响应式适配

/* 移动端优化 */

@media (max-width: 768px) {

.load-posts-trigger {

margin: 1rem 0;

padding: 0.5rem;

}

.loading-indicator {

font-size: 0.8rem;

}

.spinner {

width: 16px;

height: 16px;

}

}

系统生命周期详解

1. 初始化阶段

// 第一阶段:DOM 就绪

document.addEventListener("DOMContentLoaded", function () {

// 获取关键 DOM 元素

const postsContainer = document.getElementById("posts-container");

const loadTrigger = document.getElementById("load-posts-trigger");

// 初始化状态变量

let postsLoaded = false;

let isLoading = false;

let userInteractionDetected = false;

});

2. 用户交互检测阶段

// 第二阶段:等待用户交互

function detectUserInteraction() {

if (!userInteractionDetected) {

userInteractionDetected = true;

// 状态转换:进入智能加载阶段

startSmartLoading();

}

}

3. 智能加载阶段

// 第三阶段:多重触发机制启动

function startSmartLoading() {

// 3.1 启动 Intersection Observer

const observer = new IntersectionObserver(/* ... */);

// 3.2 启动滚动检测

window.addEventListener("scroll", handleScroll);

// 3.3 启动空闲检测

scheduleIdleLoading();

// 3.4 启动网络检测

checkNetworkStatus();

}

4. 内容加载阶段

// 第四阶段:内容加载与展示

function loadPosts() {

// 4.1 状态检查

if (isLoading || postsLoaded || !postsContainer) return;

// 4.2 设置加载状态

isLoading = true;

showLoadingIndicator();

// 4.3 内容展示

setTimeout(() => {

postsContainer.style.display = "block";

postsContainer.style.animation = "fadeInUp 0.8s ease-in-out forwards";

// 4.4 状态更新

postsLoaded = true;

isLoading = false;

// 4.5 后续优化

preloadImages();

hideLoadingIndicator();

}, 300);

}

5. 清理阶段

// 第五阶段:资源清理

function cleanup() {

// 5.1 清理观察者

if (observer) {

observer.disconnect();

observer = null;

}

// 5.2 清理定时器

if (idleTimeout) {

clearTimeout(idleTimeout);

idleTimeout = undefined;

}

// 5.3 移除事件监听

window.removeEventListener("scroll", handleScroll);

}

错误处理与兜底策略

1. 浏览器兼容性处理

// Intersection Observer 兼容性检测

if ("IntersectionObserver" in window) {

// 使用现代 API

const observer = new IntersectionObserver(/* ... */);

} else {

// 降级到滚动检测

window.addEventListener("scroll", handleScroll);

}

2. 网络状态兜底

// 网络连接检测

if ('connection' in navigator) {

const connection = (navigator as any).connection;

// 根据网络状态调整策略

} else {

// 默认策略

setTimeout(() => {

if (!postsLoaded && userInteractionDetected) {

loadPosts();

}

}, 2000);

}

性能监控与优化

1. 关键指标监控

// 性能监控

function measurePerformance() {

const navigation = performance.getEntriesByType("navigation")[0];

const fcp = performance.getEntriesByName("first-contentful-paint")[0];

console.log("页面加载时间:", navigation.loadEventEnd - navigation.loadEventStart);

console.log("首次内容绘制:", fcp.startTime);

}

2. A/B 测试支持

// 支持不同的加载策略

const loadingStrategy = {

aggressive: { threshold: 50, delay: 1000 },

normal: { threshold: 70, delay: 1500 },

conservative: { threshold: 85, delay: 2000 },

};

const currentStrategy = loadingStrategy.normal;

总结与展望

技术亮点

特性实现方式核心价值
智能化基于用户行为的自适应加载提升用户体验
多重保障多种触发机制确保可靠性确保功能稳定
性能优先充分利用浏览器原生 API最佳性能表现
用户体验平滑过渡和及时反馈提升交互感受

留作记录,方便后面再想到懒加载可以从此文借鉴经验