不能直接当组件用,因为浏览器跳过其内容解析,不渲染、不执行脚本、不加载资源、不触发data-属性绑定,仅作“休眠区”;需用document.importnode(tmpl.content, true)克隆并手动填充数据后插入dom,否则表单状态丢失且无报错。

为什么不能直接当模块用
因为浏览器遇到<template></template>会跳过解析,里面的内容不渲染、不执行<script></script>、不加载图片、不触发data-属性绑定——它只是个“休眠区”,不是组件。常见错误是把它当 Vue 的<template></template>或 Web Component 的<slot></slot>用,结果 DOM 里啥都没有,控制台也没报错,纯静默失败。
更隐蔽的坑:innerHTML = tmpl.innerHTML看似简单,但会丢掉<input checked>的选中态、<select></select>的当前选项、<textarea></textarea>的用户输入值;cloneNode(true)也一样,表单状态全归零。
怎么安全克隆并填充内容
唯一可靠方式是用document.importNode(tmpl.content, true),它能保留原生表单状态,兼容 Shadow DOM,且不会漏掉文本节点或注释。
- 获取模板:
const tmpl = document.getElementById('card-template') - 克隆内容:
const fragment = document.importNode(tmpl.content, true)(必须传true) - 填充数据:遍历
fragment.querySelectorAll('[data-bind]'),按data-bind="title"找到节点,用node.textContent = data.title或node.setAttribute('src', data.img)赋值 - 挂载:
container.appendChild(fragment),禁用innerHTML +=——否则已绑定的事件监听器全失效
如何让支持复用与属性传参
它没有生命周期、不监听属性变化,所谓“传参”就是调用 JS 工厂函数时传个对象,再手动映射到 DOM 节点。适合静态内容或低频更新场景。
实操要点:
- 模板里用
data-bind="author-name",别用class="author"——语义清晰、不易冲突 - 工厂函数返回
DocumentFragment,不是字符串,避免重复 HTML 解析 - 如需多次更新,缓存首次生成的 fragment,后续只改
textContent或dataset,不重新克隆 - 禁止硬编码
id="modal"——重复 ID 会导致document.getElementById()返回错节点,改用data-id或动态生成唯一标识
在微前端里的隔离边界在哪
<template></template>本身不隔离样式、不封装作用域,插入后所有 class 和 <style></style> 都落在 light DOM,照样被主应用 CSS 穿透。想真正隔离,必须配合attachShadow({ mode: 'closed' })。
关键动作只有两步:
- 在自定义元素构造函数里调用
this.attachShadow({ mode: 'closed' })——没这句,等于没建墙 - 把克隆后的
fragment用shadowRoot.appendChild(fragment)挂载,不是appendChild到 body - 所有子应用 CSS 必须显式注入 shadowRoot,不能靠
<link rel="stylesheet">自动生效
复杂点在于:Shadow DOM 内部无法被外部 querySelector 捕获,但外部也无法穿透样式——这个“墙”是单向的,得提前设计好通信和样式注入链路。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











