javascript基础学习系列三百三十三:创建影子 DOM
考虑到安全及避免影子 DOM 冲突,并非所有元素都可以包含影子 DOM。尝试给无效元素或者已 经有了影子 DOM 的元素添加影子 DOM 会导致抛出错误。
以下是可以容纳影子 DOM 的元素。
任何以有效名称创建的自定义元素(参见 HTML 规范中相关的定义)
<article>
<aside>
<blockquote> <body>
<div>
<footer> <h1>
<h2>
<h3>
<h4>
<h5>
<h6>
<header> <main> <nav>
<p>
<section>
<span>
影子 DOM 是通过 attachShadow()方法创建并添加给有效 HTML 元素的。容纳影子 DOM 的元素
被称为影子宿主(shadow host)。影子 DOM 的根节点被称为影子根(shadow root)。 attachShadow()方法需要一个 shadowRootInit 对象,返回影子 DOM 的实例。shadowRootInit 对象必须包含一个 mode 属性,值为"open"或"closed"。对"open"影子 DOM 的引用可以通过 shadowRoot属性在 HTML 元素上获得,而对"closed"影子 DOM 的引用无法这样获取。
下面的代码演示了不同 mode 的区别:
document.body.innerHTML = `
<div id="foo"></div>
<div id="bar"></div> 18
`;
const foo = document.querySelector('#foo');
const bar = document.querySelector('#bar');
const openShadowDOM = foo.attachShadow({ mode: 'open' }); const closedShadowDOM = bar.attachShadow({ mode: 'closed' });
20 console.log(bar.shadowRoot); // null 21
一般来说,需要创建保密(closed)影子 DOM 的场景很少。虽然这可以限制通过影子宿主访问影 子 DOM,但恶意代码有很多方法绕过这个限制,恢复对影子 DOM 的访问。简言之,不能为了安全而 创建保密影子 DOM。
使用影子 DOM
把影子 DOM 添加到元素之后,可以像使用常规 DOM 一样使用影子 DOM。来看下面的例子,这里 重新创建了前面红/绿/蓝子树的示例:
for (let color of ['red', 'green', 'blue']) {
const div = document.createElement('div');
const shadowDOM = div.attachShadow({ mode: 'open' });
document.body.appendChild(div);
shadowDOM.innerHTML = `
<p>Make me ${color}</p>
<style> p{
color: ${color};
}
</style> `;
}
console.log(openShadowDOM); // #shadow-root (open) console.log(closedShadowDOM); // #shadow-root (closed)
console.log(foo.shadowRoot); // #shadow-root (open)
注意 如果想保护独立的DOM树不受未信任代码影响,影子DOM并不适合这个需求。 对iframe施加的跨源限制更可靠。
虽然这里使用相同的选择符应用了 3 种不同的颜色,但每个选择符只会把样式应用到它们所在的影 子 DOM 上。为此,3 个
元素会出现 3 种不同的颜色。
可以这样验证这些元素分别位于它们自己的影子 DOM 中:
for (let color of ['red', 'green', 'blue']) {
const div = document.createElement('div');
const shadowDOM = div.attachShadow({ mode: 'open' });
document.body.appendChild(div);
shadowDOM.innerHTML = `
<p>Make me ${color}</p>
<style> p{
color: ${color};
}
</style> `;
}
function countP(node) {
console.log(node.querySelectorAll('p').length);
}
countP(document); // 0
for (let element of document.querySelectorAll('div')) {
countP(element.shadowRoot);
}
// 1 // 1 // 1
更多推荐


所有评论(0)