核心是分离数据获取与视图更新,通过稳定业务id标识区块、服务端客户端状态一致、轻量语义化api、按需返回html片段或json、内置加载态与降级保障实现局部刷新。

核心在于“分离数据获取与视图更新”,让页面某一块内容能独立发起请求、接收响应、渲染结果,全程不干扰其余区域。关键不是技术堆砌,而是结构设计是否支持这种解耦。
前端:用稳定标识驱动局部刷新
每个可刷新区块必须有唯一且服务端/客户端一致的标识,不能依赖随机值或运行时生成的索引。
- 组件 key 必须用业务 ID,比如 key={post.id} 或 key={`comment-${commentId}`},避免 Math.random() 或数组下标
- 服务端返回的初始 HTML 中,该区块的 props(包括 null/undefined)要和客户端 hydration 时的初始状态完全一致;推荐把初始数据序列化后写入 window.__INITIAL_DATA__
- 禁用未同步初始值的全局状态(如 zustand/store)直接驱动局部刷新;若必须用,需确保服务端已预填充 store 并随 HTML 一并下发
通信:轻量、语义明确的异步请求
局部刷新本质是“小请求换小响应”,不是全页重载的简化版,所以接口设计要匹配这个粒度。
- 优先使用 Fetch API 替代传统 XMLHttpRequest,语法简洁、原生 Promise 支持好,错误处理更可控
- 接口路径建议带语义,例如 /api/posts/123/preview 或 /api/comments/latest?limit=5,而非泛用的 /data
- 响应格式统一用 JSON,字段精简,只传当前区块需要的数据,避免冗余字段拖慢解析和渲染
服务端:按需输出片段或数据
服务器不必返回整页 HTML,而应支持两种模式:纯数据接口(供 JS 渲染),或可嵌入的 HTML 片段(供 innerHTML 直接替换)。
- 采用 Thymeleaf、Rust Tera 或 Go html/template 等支持片段(fragment)的模板引擎,定义 th:fragment="comment-list" 类型的模块,通过请求头(如 X-Requested-With: XMLHttpRequest)判断是否返回片段 HTML
- 对 API 路由,保持 RESTful 风格,返回结构化 JSON;对模板路由,支持 ?fragment=comments 这类参数,只渲染对应区块
- 注意缓存控制:局部刷新内容通常时效性强,响应头设 Cache-Control: no-cache 或带 ETag,避免旧数据残留
用户体验:加载态与降级保障
局部刷新提升了速度,但也放大了失败感知。用户看到“某一块卡住”比“整个页白屏”更困惑,因此必须有明确反馈。
- 每个刷新区块内置 loading 状态,例如显示骨架屏(skeleton)或 “正在更新…” 文案,避免空白或旧内容长期滞留
- 网络失败时提供重试按钮或自动回退机制,不要静默失败;可记录错误日志,但不向用户暴露技术细节
- 对不支持 JS 的环境(如爬虫、低配设备),确保服务端仍能完整渲染该区块——即“渐进增强”,不是“JS 依赖”










