html模板引擎不等于组件化,需配合初始化逻辑、作用域隔离和传参契约;template仅是模具,需js手动克隆与填充;mustache等库只解决静态注入;custom elements才是原生组件化方案。

HTML 模板引擎本身不等于组件化,它只是提供数据填充能力;真正实现组件化,必须配合明确的初始化逻辑、作用域隔离机制和传参契约——否则你写的只是带占位符的 HTML 字符串。
template 标签不是组件,只是模具
<template></template> 不会自动渲染,也不会解析 {{title}} 这类占位符。它只是浏览器跳过的 DOM 片段,内容不在主文档树中。
- 直接写
<template id="card"><div>{{title}}</div></template>,页面永远空白 - 必须手动调用
document.getElementById('card').content.cloneNode(true)获取文档片段 - 占位符替换得靠 JS 遍历节点 + 修改
textContent或innerHTML,不能依赖字符串 replace - 含
<input>的模板建议用document.importNode(template.content, true),避免表单重置
mustache.js 等轻量模板库适合静态数据注入
这类库解决的是「把数据塞进 HTML 字符串」的问题,但不解决生命周期、样式隔离或复用管理。
- 适合场景:构建时预渲染、邮件模板、服务端生成静态页
- 不适合场景:需要响应属性变更、监听事件、动态更新子内容的交互组件
- 示例中
mustache.render('<div>{{name}}</div>', { name: 'Alice' })返回字符串,插入后所有事件绑定丢失 - 若模板含
<script></script>,不会执行;需额外 parse +eval或创建<script></script>标签再 append
Custom Elements 才是原生组件化的最小可行解
只有 customElements.define() 注册的类,才能拥有属性监听、挂载/卸载钩子、Shadow DOM 隔离——这才是浏览器认可的“组件”。
- 组件名必须含短横线,如
'nav-bar',否则注册失败 -
constructor()里只能调用super()和this.attachShadow(),不能操作this.shadowRoot - DOM 初始化必须放在
connectedCallback(),此时元素已挂载到文档 - 想响应
title属性变化,得声明static get observedAttributes() { return ['title']; }并实现attributeChangedCallback() - Shadow DOM 默认不继承外部样式,
<slot></slot>是内容分发唯一方式,别用querySelector穿透取子元素
GoFrame/gview 或 3x-ui 的模板引擎只适用于服务端渲染
这类 Go 模板引擎(基于 html/template)运行在服务端,生成完整 HTML 后发给浏览器——它不参与客户端组件生命周期,也不提供 Shadow DOM 或属性绑定能力。
- 优势:自动 HTML 转义防 XSS、支持模板继承(
{{template "header" .}})、文件缓存提升性能 - 局限:无法响应用户操作、不能局部更新、不支持客户端传参(所有数据靠 HTTP 响应一次性注入)
- 典型结构:
layouts/base.html定义骨架,pages/index.html通过{{define "main"}}注入内容 - 它解决的是“如何组织服务端 HTML 文件”,而非“如何在浏览器里复用交互区块”
最容易被忽略的一点:组件化的核心不是“怎么拆出 HTML”,而是“谁负责初始化、传参、更新、销毁”。<template></template> 只管存结构,customElements.define() 才定义行为契约;没后者,前者只是废纸。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











