
Lit 模板引擎如何只更新变化的 DOM完整渲染流程指南【免费下载链接】litLit is a simple library for building fast, lightweight web components.项目地址: https://gitcode.com/GitHub_Trending/li/lit购物车列表每次点击刷新后整个列表节点被销毁重建、输入框里的半句话凭空消失这是手写 innerHTML 维护 UI 时的常见代价。lit-html 用带标记的静态模板加动态值占位的方式让同一段 UI 在状态变化时只改动真正变化的节点重复渲染不再触发整块 DOM 重建页面状态得以自然保留。一句话定位lit-html 是 Lit 框架里的 HTML 模板引擎用模板字面量混合静态 HTML 与动态值render()负责首屏创建与后续增量更新适合需要高频局部刷新的 Web 组件。方案更新粒度定位lit-html只写变化的动态值轻量模板引擎字符串拼接 innerHTML整段重建一次性生成原生 Web Components无模板层DOM 操作全手工平台基础一次 render 调用的完整旅程跟着通知角标走用一份真实输入当探针给容器渲染一个通知角标含状态文字、一个 class 绑定和一个点击按钮。import {html, render} from lit; const root document.querySelector(#root); const status [offline, connecting, online]; let i 0; const ui () html span class${status[i] ? status[i] : }${status[i]}/span button click${() { i (i 1) % 3; ui2(); }}切换/button;首帧渲染render(ui(0), container)之后这个角标会经历四步。每步只回答一个问题系统做了什么为什么这么做。render 入口与容器标记谁来决定复用html标签函数只做一件事把静态字符串数组和动态值数组装进一个TemplateResult对象返回。求值成本约等于一次函数调用加一次对象分配DOM 相关的事一件没干。这是刻意的标签函数越轻重复渲染的固定开销越小。入口是render()源码 packages/lit-html/src/lit-html.ts。它先读容器上的_$litPart$字段没有就往容器里插入一对标记节点、新建ChildPart存回该字段有就直接调用part._$setValue(value)。容器因此自带是否已渲染过的指纹无需额外的全局簿册。Prepare把字符串数组变成带标记的骨架首次渲染会拿strings数组作缓存键查模板缓存源码里是一个WeakMap。同一个模板字面量编译后字符串数组引用稳定所以这条键在整页生命周期内不会变。未命中时进入_$getTemplate静态串被拼成带标记的 HTML。文本位置的${}变成注释节点!--?lit$...$--属性位置的${}改写成class$lit$lit$...$形式的哨兵。属性名加后缀是防御手段防止style、class这类会被浏览器解析的属性在含标记串时产生意外行为。标记串写入template元素后由浏览器解析再深度优先遍历每发现一个标记就生成一条TemplatePart元数据记录深度优先索引、类型文本或属性和属性名。这一步只读静态串与传入的值无关所以每个模板字面量全程只执行一次产物进缓存。Create克隆骨架并让占位长出 PartTemplate被克隆到DocumentFragment文档片段游离于文档之外、可整体插入的 DOM 集合。克隆后的节点树再按深度优先索引走一遍索引与TemplatePart对应的节点上生成真正持有 DOM 引用的Part对象文本位置是ChildPart属性位置是AttributePart前缀的事件是EventPart。这些对象由TemplateInstance统一持有再挂到容器的ChildPart上下次渲染直接跳过这一步。Update只对账不同步就不写 DOM这是唯一每次渲染都执行的阶段。遍历TemplateInstance持有的Part逐个调用_$setValue(新值)。每个Part保存着上次提交的值新值与旧值相同就直接返回——零 DOM 操作。事件侧同样聪明EventPart内部用一个固定包装函数调用addEventListener只要监听器配置没变就不拆建监听即使你每次传入新的箭头函数。关键组件速查表组件职责典型场景render()入口管理容器上的根ChildPart独立模板渲染、测试Template静态骨架与TemplatePart元数据按strings缓存模板被多处引用TemplateInstance某次克隆出的片段与全部Part同一容器连续更新ChildPart文本/子节点位置的值提交与 diffhtml\${text}EventPart事件绑定复用包装监听器click绑定BooleanAttributePart按真值增删布尔属性?disabled绑定渲染旅程流程图lit-html 最小示例状态徽章三态切换import {html, render} from lit; const root document.querySelector(#root); const states [connecting, ready, offline]; let i 0; const badge () html span class${i % 2 ? on : }${states[i]}/span button click${() { i (i 1) % 3; render(badge(), root); }}切换/button; render(badge(), root);预期输出首次渲染span classconnecting/span点击一次后span classonready/span再点击span classoffline/span。三次渲染中按钮节点始终未被重建变的只有 class 和文字两个点输入或选中状态都不会丢失。进阶提示事件里频繁新建监听函数不是问题EventPart用包装器规避了拆建成本无需手写缓存。ChildPart支持array.map()出来的数组每项复用独立Part做增量更新列表渲染别退化成整串拼接。模板预编译可把 Prepare 移到构建期思路见 dev-docs/design/how-lit-html-works.md。一句话收束lit-html 把静态骨架只搭一次、动态部分各自记账做到极致这就是它轻量却快的原因。延伸阅读官方原理文档 dev-docs/design/how-lit-html-works.md、源码 packages/lit-html/src/lit-html.ts、渲染演示动画 dev-docs/images/how-lit-html-works/how-lit-works-demo.gif。【免费下载链接】litLit is a simple library for building fast, lightweight web components.项目地址: https://gitcode.com/GitHub_Trending/li/lit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考