Web Components 使用 <template> 声明可复用结构,内容不渲染、支持内联样式和 <slot>;需克隆后注入 Shadow DOM,配合 :host、属性响应与 slot 分发实现封装与复用。

Web Components 配合 <template> 定义组件结构,核心在于用模板声明结构、用 JavaScript 实例化并注入 Shadow DOM。不是直接把 template 插入页面,而是把它当作“蓝图”,每次创建组件时克隆使用。
用 <template> 声明可复用的 HTML 结构
<template> 标签本身不渲染,内容被浏览器解析但不执行、不显示,适合存放组件的默认 UI 片段。它支持内联 <style> 和 <slot>,是天然的组件模板容器。
例如:
<template id="alert-box">
<style>
:host { display: block; padding: 12px; border-radius: 4px; }
.content { margin: 0; }
.close-btn { float: right; cursor: pointer; }
</style>
<div class="alert">
<slot name="icon">⚠️</slot>
<p class="content"><slot>提示信息</slot></p>
<span class="close-btn" role="button">×</span>
</div>
</template>这个模板里:
立即学习“前端免费学习笔记(深入)”;
-
:host选择器作用于自定义元素自身(如<my-alert>) -
<slot>提供内容分发入口,支持具名插槽(如name="icon")和默认插槽 - 内联样式只在 Shadow DOM 内生效,不会污染全局
在自定义元素中加载并使用模板
在类中通过 document.getElementById() 获取模板,调用 content.cloneNode(true) 克隆其内容(避免重复使用同一份 DOM 节点),再挂载到 Shadow DOM:
class MyAlert extends HTMLElement {
constructor() {
super();
const template = document.getElementById('alert-box');
const shadow = this.attachShadow({ mode: 'open' });
shadow.appendChild(template.content.cloneNode(true));
// 绑定关闭按钮事件
const closeBtn = shadow.querySelector('.close-btn');
closeBtn.addEventListener('click', () => this.remove());
}
}
customElements.define('my-alert', MyAlert);关键点:
- 必须用
cloneNode(true),否则模板内容被移走后无法复用 -
shadow.appendChild(...)是推荐做法,比shadow.innerHTML = ...更安全(避免 XSS 风险且保留事件绑定能力) - 模板 ID 需全局唯一,建议与组件名一致(如
id="my-alert-template")
支持动态内容与属性响应
模板本身是静态的,但可通过属性控制行为。比如添加 type 属性改变背景色:
<my-alert type="error">操作失败,请重试</my-alert>
在组件中读取并应用:
connectedCallback() {
const type = this.getAttribute('type') || 'info';
this.shadowRoot.querySelector('.alert').style.backgroundColor =
type === 'error' ? '#ffebee' : '#e3f2fd';
}也可以配合 attributeChangedCallback 实现属性变更时自动更新。
注意 slot 内容的实际渲染位置
外部传入的内容会“穿透”进 Shadow DOM 的对应 <slot> 中,但:
- slot 内容仍属于 Light DOM,样式继承自外层(除非显式重置)
- 若未提供内容,显示模板中
<slot>的默认文本或子节点 - 多个同名 slot 会被合并到第一个 slot 位置(浏览器自动分发)
比如这样使用:
<my-alert type="success"> <span slot="icon">✅</span> <strong>提交成功!</strong> </my-alert>
会把 ✅ 插入 icon slot,<strong> 替换默认 slot 内容。
不复杂但容易忽略



















