Web Components 和 Shadow DOM **并不使用 <iframe>
**,尽管它们在某些方面(如封装性)看起来类似。让我们详细区分一下它们:
✅ Web Components 和 Shadow DOM 的本质
Web Components 是一组前端 API,包括:
Custom Elements
(自定义元素)Shadow DOM
(影子 DOM)HTML Templates
(模板)
Shadow DOM 提供了 封装样式和结构 的能力,使组件内部的 DOM 和样式不会影响外部,也不被外部影响。
关键点:Shadow DOM 是运行在主文档上下文中的 DOM 树,并非独立的文档环境。
❌ iframe 的作用和区别
<iframe>
会嵌入一个完全独立的 浏览器上下文(包括 JS 执行环境、CSS、全局变量等)。- 它和主页面之间的隔离程度远高于 Shadow DOM,属于“进程级别”的隔离(安全沙箱)。
- 适用于嵌入第三方页面、广告、或完全隔离的内容。
🔍 对比总结表
特性 | Shadow DOM | <iframe> |
---|---|---|
是否隔离样式 | ✅ 是(封装) | ✅ 是(完全隔离) |
是否隔离 JS 作用域 | ❌ 否(共享全局作用域) | ✅ 是(独立 JS 环境) |
是否是独立文档 | ❌ 否 | ✅ 是(有自己的 document ) |
加载性能影响 | ✅ 轻量 | ❌ 较重,尤其是多个 iframe |
常用于 | UI 组件封装、Design Systems | 广告、嵌入外部内容、跨域内容展示 |
✅ 举个例子:Shadow DOM
1 | <my-component></my-component> |
上面这个组件中的 <p>
标签样式不会影响页面其他内容,也不会被外部样式污染 —— 但它仍运行在主页面的上下文中,不是通过 iframe 实现的。
🧠 总结一句话:
Shadow DOM 是“样式和 DOM 封装”,而 iframe 是“运行环境级别的隔离”。两者不是一回事,Shadow DOM 不使用 iframe。
✅ 一、目标:将组件资源拆分为多个文件
比如:
my-component.js
:定义组件逻辑my-component.html
:定义模板结构my-component.css
:定义样式
✅ 二、实现方式:使用 JavaScript 动态加载外部资源
📄 my-component.html
1 | <template> |
📄 my-component.css
1 | .greeting { |
📄 my-component.js
1 | class MyComponent extends HTMLElement { |
📄 使用:
1 | <script type="module" src="my-component.js"></script> |
✅ 三、好处
- 结构清晰:HTML、CSS、JS 分离,便于维护
- 可重用性高:可作为独立模块复用
- 保持封装性:依旧使用 Shadow DOM,样式不会外泄
⚠️ 注意事项
- 跨域问题:资源必须允许浏览器访问(同源或正确 CORS 设置)。
- 性能:每次创建组件都可能触发 fetch,可使用缓存或优化加载逻辑。
- 资源依赖:需要确保 CSS 和 HTML 文件在 JS 加载之前可访问。
this.attachShadow({ mode: 'open' })
、Promise.all()
是原生 Web 技术的一部分,
而 Vue、React、Angular 这类框架有自己独特的抽象和机制。
🔍 一句话总结:
原生 Web Components 用浏览器原生 API(如 Shadow DOM、Custom Elements)来封装组件;
Vue、React、Angular 则用自己设计的“组件系统”来实现相似目的,但不依赖 Shadow DOM(默认情况下)。
✅ 对比核心区别
特性/行为 | 原生 Web Components | Vue / React / Angular |
---|---|---|
组件机制 | 使用 class + customElements |
使用框架语法(如 Vue SFC、JSX、TSX) |
封装 DOM(结构) | 使用 Shadow DOM |
使用虚拟 DOM(VNode),默认非封装 |
封装样式(CSS 隔离) | 自动隔离 via Shadow DOM | 使用 CSS Modules、Scoped CSS、JSS |
attachShadow({mode}) |
显式调用以开启封装 | 没有这个 API,框架自动管理 |
异步加载(如 Promise.all ) |
使用浏览器 API | 通常用 async/await 或框架方式(hooks、lifecycle) |
运行时依赖 | 无(原生浏览器支持) | 依赖框架运行时(Vue、React 等) |
🧪 举个例子比较一下:
🌐 原生 Web Component
1 | class MyComponent extends HTMLElement { |
⚛️ React 组件(等价实现)
1 | function MyComponent() { |
React 不使用 Shadow DOM,而是通过虚拟 DOM 管理结构,靠 JS 隔离样式或使用模块化 CSS。
🤔 那为什么框架不用 Shadow DOM 呢?
✅ 优点(不用的原因):
- 性能问题:Shadow DOM 创建成本较高,虚拟 DOM 更易批量优化。
- 工具生态好:框架有更强的开发体验(如 HMR、TypeScript 支持)。
- 灵活性高:组件样式、结构更可控,不依赖浏览器底层 API。
- 跨平台渲染支持更好(如 SSR、React Native)。
❗但:框架也可以使用 Shadow DOM
- Vue 和 Angular 可以启用
shadow DOM
模式(shadow: true
)。 - React 可以封装原生 Web Components 并渲染到 Shadow Root。
但这通常只在特定场景下使用,如构建设计系统、嵌入外部平台等。
✅ 总结
对比点 | 原生 Web Components | Vue/React/Angular |
---|---|---|
是否使用 Shadow DOM | ✅ 默认使用 | ❌ 默认不使用(可选启用) |
是否使用 Promise.all | ✅ 直接用原生 API | ✅ 也用,但通常包在生命周期钩子中 |
封装性 | ✅ 强,原生封装 | ❌ 默认弱,用工具实现封装 |
上手难度 | 🚧 较高,需手写底层逻辑 | ✅ 更高层抽象,开发体验好 |
赏
使用支付宝打赏
使用微信打赏
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏