前端【免费下载链接】beakerAn experimental peer-to-peer Web browser项目地址https://gitcode.com/gh_mirrors/be/beaker点击查看免费下载导读lit-html 是 Polymer Project 推出的轻量级 HTML 模板渲染库它允许开发者直接使用 JavaScript 的模板字面量Template Literals编写 HTML 模板并借助模板标签Tagged Template将动态表达式精确映射到 DOM 的对应位置实现只更新变化部分的高效渲染。本文以 app/fg/vendor/lit-element/lit-html/README.md 为骨架结合 Beaker 仓库中完整内置的 lit-html 源码讲解其安装方式、html/render核心 API、模板编译缓存、Part 更新机制、指令系统与哨兵值等底层原理并展示它在 Beaker 浏览器前端界面如地址栏、导航栏中的真实应用方式。读完本文你将掌握 lit-html 的完整使用范式并理解它为何能以极小的体积实现细粒度的 DOM 增量更新。lit-html 是什么用模板字面量写 HTML 模板lit-html让你在 JavaScript 中以模板字面量直接编写 HTML 模板。它的模板就是纯 JavaScript——既保留了书写 HTML 的熟悉感又拥有 JavaScript 的全部表达能力。lit-html 负责把模板高效渲染到 DOM并在传入新值时高效地更新 DOM 中对应的部分。在 Beaker 仓库中lit-html 以 vendor 形式随 lit-element 一并内置源码入口位于 app/fg/vendor/lit-element/lit-html/lit-html.js核心实现分布在 app/fg/vendor/lit-element/lit-html/lib 目录下的template-result.js、render.js、template.js、parts.js、template-factory.js、template-instance.js、directive.js等模块中。快速上手第一个 lit-html 模板README 给出了最经典的入门示例——定义一个接收参数并返回模板的函数然后通过render渲染到页面。这个例子完整展示了 lit-html 的两大核心能力模板复用与局部更新。import {html, render} from lit-html; // 这是一个 lit-html 模板函数。它返回一个 lit-html 模板。 const helloTemplate (name) htmldivHello ${name}!/div; // 渲染出 divHello Steve!/div 到 document.body render(helloTemplate(Steve), document.body); // 更新为 divHello Kevin!/div但只更新 ${name} 部分 render(helloTemplate(Kevin), document.body);注意第二次render的注释虽然整个模板函数被重新求值但 DOM 中只有${name}对应的文本节点被更新其余静态结构div标签等完全复用。这正是 lit-html 与整段 innerHTML 重写方案的本质区别。两大核心导出html与renderlit-html 对外提供两个核心导出html一个 JavaScript 模板标签用于产生TemplateResult——一个承载模板本身 需要填充进模板的值的容器对象。render()把TemplateResult渲染到某个 DOM 容器元素或 Shadow Root中的函数。从源码看这两个导出的实现非常直接。在 lit-html.js 中export const html (strings, ...values) new TemplateResult(strings, values, html, defaultTemplateProcessor); export const svg (strings, ...values) new SVGTemplateResult(strings, values, svg, defaultTemplateProcessor);html只是把模板字面量拆出的静态字符串数组strings与插值values打包成TemplateResult实例。TemplateResult在 lib/template-result.js 中定义它持有四个字段strings静态字符串、values动态值、type模板类型标识html或svg、processor模板处理器。其中getHTML()方法负责把表达式标记嵌入静态字符串生成最终的 HTML 字符串getTemplateElement()则通过document.createElement(template)把该字符串解析为一个template元素作为后续克隆与实例化的模板源。render的实现位于 lib/render.jsexport const render (result, container, options) { let part parts.get(container); if (part undefined) { removeNodes(container, container.firstChild); parts.set(container, part new NodePart(Object.assign({ templateFactory }, options))); part.appendInto(container); } part.setValue(result); part.commit(); };这里的关键机制是render内部维护了一个partsWeakMap以容器 DOM 节点为键缓存对应的NodePart。首次渲染时清空容器并创建NodePart后续对同一容器再次调用render时直接复用已缓存的NodePart调用setValuecommit完成增量更新。因此更新只影响变化部分的承诺是由NodePart的提交逻辑保证的而非每次重建整棵 DOM。安装方式作为独立的 npm 包lit-html 的安装只需一条命令$ npm install lit-html在 Beaker 仓库中它则作为第三方 vendor 依赖直接以源码形式内置使用时通过相对路径导入例如 app/fg/shell-window/navbar.js 中的import {LitElement, html, css} from ../vendor/lit-element/lit-element import {classMap} from ../vendor/lit-element/lit-html/directives/class-map即html从 lit-element 重导出lit-element 内部基于 lit-html指令如classMap则直接从 lit-html 的directives/目录导入。模板编译与缓存Template、TemplateInstance、templateFactorylit-html 性能的核心在于模板只编译一次之后无限复用。其流程可概括为三步编译Template类lib/template.js通过TreeWalker遍历template内容找出所有嵌有表达式的文本位置与属性位置记录为parts数组每个 part 包含类型attribute/node、节点索引、属性名、静态字符串等并把普通文本拆分、把动态位置替换为注释型 marker。缓存templateFactorylib/template-factory.js以result.type result.strings为键缓存已编译的Template。缓存分两层WeakMapstringsArray直接按TemplateStringsArray对象查找MapkeyString把静态字符串用 marker 拼接成键再查找。这意味着即使模板函数每次重新执行只要静态结构一致就命中同一份编译结果。实例化TemplateInstancelib/template-instance.js克隆缓存的模板片段并按Template.parts的索引在克隆节点上创建对应的 Part 对象文本 Part、属性 Part 等。每次渲染时update(values)依次对每个 PartsetValue再commit完成值到 DOM 的写入。值得注意的实现细节是表达式 marker。在 lib/template.js 中export const marker {{lit-${String(Math.random()).slice(2)}}}; export const nodeMarker !--${marker}--; export const boundAttributeSuffix $lit$;marker 在每次加载时由随机数生成用于避免与模板中可能出现的真实文本冲突nodeMarker是注释形式的标记用于文本位置、多绑定属性以及包含类标记文本值的属性所有被绑定的属性名都会追加$lit$后缀以避开 IE11 与 Edge 对style、SVG 属性等做的特殊属性值解析见 lib/template-result.js 的getHTML()。Part 更新机制NodePart 与五种 Part 类型只更新变化部分的落地执行者是各类 Part。Part 是 lit-html 中连接值与DOM 位置的抽象每种 Part 处理一种绑定场景Part 类型绑定场景更新行为NodePart文本节点/子节点位置如div${expr}/div值比较后只替换文本或节点可嵌套渲染模板、节点、可迭代对象AttributePart普通 HTML 属性如title${x}惰性提交仅当值变化时调用setAttributeBooleanAttributePart布尔属性如disabled${x}真值则setAttribute(name, )假值则removeAttributePropertyPartDOM 属性?value${x}形式之外由处理器决定直接赋值element[name] valueEventPart事件监听如click${handler}自动addEventListener/removeEventListener支持capture/passive/once选项以最核心的NodePartlib/parts.js为例它的commit()会对值进行分类处理原始值primitive与上次值不同时才更新文本节点TemplateResult若当前实例的模板与新模板相同仅调用update(values)做增量更新否则克隆新模板实例并整体替换Node直接插入该节点可迭代对象/数组为每个元素维护子NodePart复用已存在的 Part 并截断多余的旧 Part——这正是array.map((i) html${i})这类列表渲染能够高效更新的原因nothing哨兵值清空整个 Part 内容。NodePart通过appendInto/insertAfterNode等在容器中放置一对注释 marker 作为起点与终点clear()用removeNodes移除两者之间的所有节点lib/parts.js。AttributePart的惰性提交也值得注意AttributeCommitter维护dirty标记只有值真正变化且非指令、非noChange时才执行element.setAttribute避免无意义的属性写操作lib/parts.js。指令Directive系统与内置指令指令是 lit-html 扩展渲染行为的高级机制。directive()工厂函数lib/directive.js把一个工厂函数标记为指令使其在渲染时被当作指令调用而非作为值写入 DOMexport const directive (f) ((...args) { const d f(...args); directives.set(d, true); return d; });指令返回的函数在 Part 的commit()阶段被调用while (isDirective(value)) directive(part)从而可以接管 Part 的写入逻辑实现条件更新、缓存、异步替换等能力。仓库内置了 10 个官方指令位于 app/fg/vendor/lit-element/lit-html/directives 目录async-append异步渲染可迭代值追加到之前内容之后async-replace异步渲染可迭代值替换之前内容cache在渲染不同模板时缓存旧的模板实例切换回来时直接复用避免重建class-map根据对象属性真值动态增删 CSS 类guard仅当依赖值变化时才重新渲染if-defined值为undefined时不设置属性repeat基于 key 高效重排/更新列表style-map根据对象属性真值动态设置内联样式unsafe-html把字符串作为 HTML 直接插入注意不做转义需谨慎使用until在 Promise resolve 之前渲染占位内容resolve 后渲染最终内容。以class-map为例directives/class-map.js它要求必须用在class属性且是该属性唯一的绑定export const classMap directive((classInfo) (part) { // 校验必须作用于 class 属性的 AttributePart 且是唯一绑定 ... // 处理静态 class if (!classMapStatics.has(part)) { part.committer.element.className part.committer.strings.join( ); classMapStatics.set(part, true); } // 移除旧对象中已不存在的类 ... // 按真值 toggle 新类 part.committer.element.classList.toggle(name, Boolean(classInfo[name])); });Beaker 前端大量使用了这类指令。例如 app/fg/location-bar/index.js 用classMap根据当前选中项高亮地址栏自动补全结果var rowCls classMap({ result: true, selected: i this.currentSelection })同文件还使用了repeat渲染搜索结果列表、unsafeHTML渲染搜索结果标题中带高亮片段的 HTMLapp/fg/location-bar/index.js 与 app/fg/location-bar/index.js。哨兵值noChange与nothinglit-html 定义了两个特殊的哨兵对象lib/part.jsnoChange表示该值已由指令处理、不应写入 DOM。当某个值等于noChange时Part 的commit()会直接返回跳过所有 DOM 操作例如 lib/parts.js 中if (value noChange) return;。nothing表示清空此 Part 的全部内容。NodePart.commit()检测到nothing时执行this.clear()lib/parts.js。二者配合指令使用可实现本次不更新与渲染空内容两种精确控制。SVG 模板支持除了htmllit-html 还导出svg标签用于渲染 SVG 片段。其实现SVGTemplateResultlib/template-result.js先把内容包进svg标签以在 SVG 命名空间下解析随后在getTemplateElement()中移除包裹的svg元素并把子节点重新挂回模板内容从而保证最终克隆出的片段不含多余外壳export class SVGTemplateResult extends TemplateResult { getHTML() { return svg${super.getHTML()}/svg; } getTemplateElement() { const template super.getTemplateElement(); const content template.content; const svgElement content.firstChild; content.removeChild(svgElement); reparentNodes(content, svgElement.firstChild); return template; } }版本状态与 API 稳定性按照 README 的说明lit-html处于积极开发中尚未发布 1.0 版本内部 API 仍可能发生变化但html与render两个对外 API 是稳定的。仓库内置源码在 lit-html.js 中登记了版本号1.0.0推入window.litHtmlVersions数组供依赖方检测版本与 README 所述尚未 1.0 正式发布的开发状态一致。其更新历史可参阅 CHANGELOG.md。在 Beaker 中的真实应用场景lit-html 在 Beaker 浏览器中并非孤立存在而是与 lit-element基于 lit-html 的 Web Component 基类app/fg/vendor/lit-element/lit-element.js配合构成全部内置 UI 的渲染基础。以下两个文件是典型实例导航栏 app/fg/shell-window/navbar.jsShellWindowNavbar继承LitElement声明activeTabIndex、activeTab、isSidebarHidden等响应式属性并在render()中用html模板与classMap指令组合出完整的浏览器导航界面——属性一旦变化lit-element 即触发基于 lit-html 的增量重渲染。地址栏 app/fg/location-bar/index.jsLocationBar同样继承LitElement其render()用html模板一次性描述搜索框、搜索引擎列表与自动补全结果区并用${...}插值表达式嵌入results、hoveredSearch等状态配合repeat列表、classMap选中态高亮与unsafeHTML带高亮标记的标题完整演示了模板声明 指令控制的 UI 编写范式。如果你希望在 Beaker 前端新增界面组件可直接复用这一成熟模式继承LitElement编写 Web Component用html模板描述结构用属性驱动更新用classMap/repeat/styleMap等指令处理条件样式与列表即可获得高效的增量渲染。小结lit-html 用一套极简 APIhtmlrender把HTML 模板与JavaScript 表达式无缝融合模板在首次使用时编译并缓存之后每次渲染仅通过 Part 机制更新发生变化的最小 DOM 片段指令系统则提供了列表、条件类名、异步内容、HTML 注入等高级能力的扩展点。在 Beaker 仓库中它不仅作为独立的 vendor 库完整内置更通过与 lit-element 的组合驱动了导航栏、地址栏等核心界面是一个小而精、实用且可深入阅读源码的模板渲染引擎范本。赞分享前端【免费下载链接】beakerAn experimental peer-to-peer Web browser项目地址https://gitcode.com/gh_mirrors/be/beaker点击查看免费下载相关推荐深入解析Lit-html现代Web组件模板引擎的革命深入解析Lit html现代Web组件模板引擎的革命 Lit html作为现代Web组件生态系统的核心模板引擎代表了JavaScript模板技术的一次重大革前端UI组件【亲测免费】 探索 lit-html轻量级且高效的前端模板引擎探索 lit html轻量级且高效的前端模板引擎 是一个由 Polymer 团队开发的轻量级、高性能的 JavaScript 库用于生成和更新 HTML 模前端UI组件Handlebars.js强大的模板引擎简化HTML渲染Handlebars.js强大的模板引擎简化HTML渲染 Handlebars.js 是一款轻量级且灵活的JavaScript模板语言用于生成静态HTML前端上一篇OpCore-Simplify让黑苹果配置从技术挑战变为轻松体验下一篇5分钟掌握用Input Leap实现一套键盘鼠标控制Windows、macOS和Linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考