概念
官方:https://developer.mozilla.org/zh-CN/docs/Web/API/Web_components/Using_shadow_DOM
核心:影子 DOM(Shadow DOM)允许你将一个 DOM 树附加到一个元素上,并且使该树的内部对于在页面中运行的 JavaScript 和 CSS 是隐藏的。
如何创建 Shadow DOM
下面的页面包含两个元素,一个 id 属性为 “host” 的
元素,以及一个包含了一些文本的
元素:
<div id="host"></div>
<span>I'm not in the shadow DOM</span>
我们将把 Shadow DOM 插入到 id=host 的元素上
const host = document.querySelector("#host");
// 创建一个 shadow dom, open 表示dom内部的细节是可见的
const shadow = host.attachShadow({ mode: "open" });
// 创建 span 并添加文本
const span = document.createElement("span");
span.textContent = "I'm in the shadow DOM";
// 将 span 元素插入到 shadow dom
shadow.appendChild(span);
界面效果是这样的:
如果页面中代码有功能代码,会将文本设置为大写
则不会影响到 shadow dom 的文本
DEMO:
需求:
- 使用fetch拿到本地的html文件,并将 html 解析为DOM
- 将解析后的内容插入到 shadowRoot
import React, { useEffect, useRef, useState } from 'react';
import './App.css';
function App() {
const container = useRef(null);
const [html, setHtml] = useState(null)
const fetchHTML = () => {
// 使用 fetch 加载 HTML 文件
fetch(`${process.env.PUBLIC_URL}/demo.html`)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.text(); // 将响应处理为文本
})
.then(html => {
setHtml(html)
// 将html解析为dom
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
//创建 shadowRoot
const container = document.getElementById('host');
const shadowRoot = container.attachShadow({ mode: 'open' });
// 由于样式隔离 需要单独提取style 再插入
// Shadow DOM 的样式是封闭的,需要显式地将样式添加到 Shadow DOM 中
const styles = doc.querySelectorAll('style');
styles.forEach(style => {
shadowRoot.appendChild(style.cloneNode(true));
});
// 将解析后的内容插入到 shadowRoot 中
while (doc.body.firstChild) {
shadowRoot.appendChild(doc.body.firstChild);
}
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});
}
fetchHTML()
return (
<div className="App">
<div className="left">
<pre>
<code>{html}</code>
</pre>
</div>
<div id='host' className="right" ref={container}></div>
</div>
);
}
export default App;