/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}

2.8 Web Components 基础
Web Components 是浏览器原生支持的组件化标准体系,允许开发者创建可复用、强封装的自定义 HTML 元素,核心由 Shadow DOM、自定义元素、HTML Template 三大技术构成。
它实现了组件级的样式隔离、结构封装与原生级复用,无需依赖前端框架即可实现跨项目、跨技术栈的组件复用,是原生前端组件化的底层标准。
2.8.1 Shadow DOM 影子 DOM
Shadow DOM 是 Web Components 的核心封装机制,它可以在普通 DOM 元素内部创建一个独立、与外部文档 DOM 树隔离的影子 DOM 子树。
内部的样式、DOM 结构不会污染外部页面,外部的全局样式也不会渗透到组件内部,从浏览器原生层面解决了组件样式冲突、DOM 结构干扰的问题。
一、基础使用语法
通过元素的 attachShadow() 方法挂载影子 DOM,返回影子根节点 shadowRoot,后续所有 DOM 操作都在影子根内部完成。
// 获取宿主元素
const host = document.querySelector('.component-host');
// 挂载影子 DOM
const shadowRoot = host.attachShadow({
mode: 'open' // 开放模式,外部可访问影子根
});
// 向影子 DOM 中插入结构与样式
shadowRoot.innerHTML = `
<style>
.card { color: #1677ff; }
/* 内部样式仅在影子 DOM 内生效,不会影响外部 */
</style>
<div class="card">
<slot></slot>
</div>
`;
二、mode 封装模式
Shadow DOM 提供两种封装模式,对应不同的外部访问权限:
|
mode 取值 |
外部访问性 |
适用场景 |
|
open |
外部可通过 host.shadowRoot 访问影子 DOM 内部 |
通用组件场景,便于外部交互与调试 |
|
closed |
外部无法获取影子根,host.shadowRoot 返回 null |
强封装场景,禁止外部操作组件内部结构 |
三、核心特性
四、slot 插槽机制
插槽是 Shadow DOM 的内容分发接口,用于承载外部传入的子元素,支持默认内容与具名插槽。
<!– 外部使用组件时传入内容 –>
<custom-card>
<span slot="title">卡片标题</span>
<p>卡片正文内容</p>
</custom-card>
// 影子 DOM 内部定义插槽位置
shadowRoot.innerHTML = `
<div class="card">
<h3 class="card-title">
<slot name="title">默认标题</slot>
</h3>
<div class="card-body">
<slot>默认正文内容</slot>
</div>
</div>
`;
2.8.2 自定义元素基础
自定义元素(Custom Elements)允许开发者定义全新的 HTML 标签,通过继承原生 HTMLElement 类实现自定义标签的行为与业务逻辑,配合 Shadow DOM 即可实现完整的原生组件,是 Web Components 的核心载体。
一、定义与注册流程
// 定义自定义元素类
class CustomButton extends HTMLElement {
constructor() {
super(); // 必须先调用父类构造函数
// 挂载 Shadow DOM
const shadow = this.attachShadow({ mode: 'open' });
// 组件结构与样式
shadow.innerHTML = `
<style>
.btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
background: #1677ff;
color: #fff;
cursor: pointer;
}
</style>
<button class="btn">
<slot></slot>
</button>
`;
}
// 元素被插入到 DOM 时触发
connectedCallback() {
console.log('自定义按钮已挂载到页面');
}
// 元素从 DOM 移除时触发
disconnectedCallback() {
console.log('自定义按钮已从页面卸载');
}
}
// 注册自定义标签,标签名必须包含横杠
customElements.define('custom-button', CustomButton);
注册后即可直接在 HTML 中像原生标签一样使用:
<custom-button>确认提交</custom-button>
二、核心生命周期钩子
自定义元素提供了标准化的生命周期钩子,用于管控组件不同阶段的逻辑:
|
生命周期方法 |
触发时机 |
典型用途 |
|
constructor() |
元素实例创建时 |
初始化状态、挂载 Shadow DOM、绑定内部事件 |
|
connectedCallback() |
元素被插入到 DOM 文档时 |
请求数据、添加全局监听、初始化第三方依赖 |
|
disconnectedCallback() |
元素从 DOM 文档移除时 |
清理定时器、移除全局监听、销毁资源 |
|
attributeChangedCallback(name, oldVal, newVal) |
监听的属性发生变化时 |
响应属性变化,同步更新组件状态 |
三、核心特点
四、典型应用场景
- 基础 UI 组件库:按钮、弹窗、表单控件等通用基础组件,实现跨框架复用。
- 微前端场景:不同技术栈项目之间的组件共享与嵌入,避免重复开发。
- 第三方嵌入组件:提供给外部页面嵌入的小组件,样式隔离无冲突。
- 业务模块封装:将复杂业务模块封装为独立标签,降低系统耦合度。


