我需要从 Shadow DOM 中获取元素并对其进行更改。我该如何做到?
<div>
<input type="range" min="100 $" max="3000 $">
</div>
<div>
<input type="range" min="100 $" max="3000 $">
</div>
您无法访问由浏览器创建以显示控件的Shadow DOM,这在Dev工具中称为#shadow-root(user-agent)
。 <input>
是其中一个例子。
您只能通过{ mode: 'open' }
选项访问开放式自定义 Shadow DOM(即您自己创建的DOM)。
element.attachShadow( { mode: 'open' } )
更新
对于大多数 UX 标准的 HTML 元素来说是正确的:<input>
、<video>
、<textarea>
、<select>
、<audio>
等。
2022 年第三方编辑
以下内容可能有助于说明问题。假设在 HTML 文档中只有一个 <input type=range>
,则此代码显示其是否可以访问子元素。
// returns 1 as expected since only one input element is in the document
document.querySelectorAll("input").length;
// get a reference to <input type=range>
var rangeInput = document.querySelector("input");
// Is it a shadowRoot?
// if null then either
// - it is not a shadowRoot OR
// - its elements can not be accessed (mode == closed)
console.log(rangeInput.shadowRoot); // returns null
上述代码显示,无法访问 <input type=range>
的内部。
回答OP问题的通用版本:
感觉阴影根API仍然不足。它似乎使querySelectorAll
无用,因为querySelectorAll
将不会再获取所有匹配的元素,因为它忽略了shadowRoots
中的所有后代。也许有一个API可以解决这个问题,但是由于我没有找到任何API,所以我自己写了一个:
这个函数递归地迭代所有的shadowRoots
,并获取你在页面上所有匹配的元素,而不仅仅是单个shadowRoot
的元素。
/**
* Finds all elements in the entire page matching `selector`, even if they are in shadowRoots.
* Just like `querySelectorAll`, but automatically expand on all child `shadowRoot` elements.
* @see https://dev59.com/PlkT5IYBdhLWcg3wX-Zo#71692555
*/
function querySelectorAllShadows(selector, el = document.body) {
// recurse on childShadows
const childShadows = Array.from(el.querySelectorAll('*')).
map(el => el.shadowRoot).filter(Boolean);
// console.log('[querySelectorAllShadows]', selector, el, `(${childShadows.length} shadowRoots)`);
const childResults = childShadows.map(child => querySelectorAllShadows(selector, child));
// fuse all results into singular, flat array
const result = Array.from(el.querySelectorAll(selector));
return result.concat(childResults).flat();
}
// examples:
querySelectorAllShadows('td'); // all `td`s in body
querySelectorAllShadows('.btn') // all `.btn`s in body
querySelectorAllShadows('a', document.querySelector('#right-nav')); // all `a`s in right menu
这里有一个例子:
var container = document.querySelector('#example');
//Create shadow root !
var root = container.createShadowRoot();
root.innerHTML = '<div>Root<div class="test">Element in shadow</div></div>';
//Access the element inside the shadow !
//"container.shadowRoot" represents the youngest shadow root that is hosted on the element !
console.log(container.shadowRoot.querySelector(".test").innerHTML);
演示:
var container = document.querySelector('#example');
//Create shadow root !
var root = container.createShadowRoot();
root.innerHTML = '<div>Root<div class="test">Element in shadow</div></div>';
//Access the element inside the shadow !
console.log(container.shadowRoot.querySelector(".test").innerHTML);
<div id="example">Element</div>
希望这可以对您有所帮助。
"message": "TypeError: container.createShadowRoot is not a function"
- JoltacreateShadowRoot
是非标准且已弃用的。Firefox和Safari都不支持它。不要使用它。而是使用element.attachShadow({mode:'open'});
。 - connexo
element.shadowRoot
表示托管在元素上的最年轻的影子根。 - Ismail RBOUH