必须写在自定义元素内,浏览器自动将其内容作为 open 模式 shadow root 渲染,不执行 JS、不加载资源;内置元素如 不支持,样式和 需写在 template 内,适用于 SSR 和静态 HTML 场景。

template 标签怎么配合 shadowroot 属性用?
直接在 <template></template> 上加 shadowroot 属性,是声明式 Shadow DOM 的核心用法。它不是“把 template 当作普通模板来克隆”,而是让浏览器原生识别:这个 <template></template> 的内容要立刻作为宿主元素的 shadow root 渲染,且不执行 JS、不加载资源(除非显式写入)。
常见错误是把它当 document.importNode() 的替代品 —— 实际上它绕过了 JS 初始化阶段,更适合 SSR 和静态 HTML 场景。
-
shadowroot必须写在<template></template>标签上,不能写在宿主元素上 - 宿主元素必须是自定义元素(如
<my-button></my-button>),不能是<div> 或 <code><p></p>等内置标签 -
mode只支持"open";"closed"不被声明式语法支持 - 浏览器会自动将
<template></template>内容挂载为 shadow root,并清空宿主元素的 light DOM - 检查控制台不会报错,但
div.shadowRoot是null - 想快速验证是否生效?查宿主元素的
shadowRoot属性是否为ShadowRoot实例 - 若需对内置元素附加 Shadow DOM,只能用
attachShadow(),且部分内置元素(如<img alt="HTML template标签的影子DOM应用?Web组件内部结构定义" >、<span></span>)根本不允许 -
<style></style>必须写在<template></template>内部,外部<style></style>不会进入 shadow DOM -
<slot></slot>名称必须与宿主元素内对应内容的slot属性值匹配,否则 fallback 内容生效 - 不支持动态修改
<template></template>内容 —— 浏览器解析完就固化了,后续改 innerHTML 无效 - 声明式只解决结构+样式的“静态封装”,行为逻辑仍需 JS 补全
- 若用 React/Vue 等框架,它们目前基本不生成声明式 Shadow DOM,得手动桥接
- CDN 或静态站点生成器(如 Astro、Hugo)可直接输出带
shadowroot的 HTML,零 JS 即可渲染隔离视图
为什么不能在 div 上用 template + shadowroot?
因为规范明确限定:只有**自定义元素**(通过 customElements.define() 注册过的)才能作为声明式 Shadow DOM 的宿主。这是硬性限制,不是兼容性问题。
如果你写了:<div><template shadowroot="open"><p>hello</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20d3191a227.jpg" alt="DeepBI DHTML 页面生成器" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器">DeepBI DHTML 页面生成器</a>
<p>生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力:
- 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面;
- 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”;
- 提及位于 `apps/console/src/featur</p>
</div>
<a href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div>
<p><span>立即学习</span>“<a href="https://pan.quark.cn/s/cb6835dc7db1" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)</a>”;</p></template></div>
浏览器会完全忽略 shadowroot 属性,<p></p> 会作为普通子节点渲染在 light DOM 中。
声明式 Shadow DOM 的样式和 slot 怎么写?
写法和 JS 创建的 Shadow DOM 完全一致,但要注意解析时机:所有样式和 <slot></slot> 都在 HTML 解析阶段就位,不依赖 JS 执行。
示例:<my-card><template shadowroot="open"><style>.card { padding: 12px; }</style>
<div class="card">
<slot name="header">默认标题</slot><slot>默认内容</slot>
</div></template></my-card>
服务端渲染时 template + shadowroot 的实际价值在哪?
关键点在于:无需等待 JS 加载和执行,HTML 字符串一返回就能呈现封装好的组件结构和样式。这对首屏性能和 SEO 很重要。
但容易被忽略的是——如果组件需要响应式逻辑或事件绑定,你仍得在 JS 中补上:customElements.define('my-card', class extends HTMLElement { connectedCallback() { this.shadowRoot.querySelector('button').onclick = () => { /* ... */ }; } });


















