简体   繁体   English

如何使用 JavaScript 在用户代理影子根中获取元素?

[英]How to get element in user-agent shadow root with JavaScript?

I need get elements from Shadow DOM and change it.我需要从 Shadow DOM 中获取元素并对其进行更改。 How i can do it?我该怎么做?

<div>
     <input type="range" min="100 $" max="3000 $">
</div>

You cannot access a Shadow DOM created by the browser to display a control, that is called a #shadow-root (user-agent) in the Dev Tools.您无法访问由浏览器创建的 Shadow DOM 来显示控件,在开发工具中称为#shadow-root (user-agent) <input> is one example. <input>就是一个例子。

You can only access open custom Shadow DOM (the ones that you create yourself), with the { mode: 'open' } option.您只能使用{ mode: 'open' }选项访问打开的自定义 Shadow DOM(您自己创建的)。

element.attachShadow( { mode: 'open' } )

Update更新

It's true for most UX standard HTML elements: <input> , <video> , <textarea> , <select> , <audio> , etc.大多数 UX 标准 HTML 元素都是如此: <input><video><textarea><select><audio>等。

3rd party edit 2022第 3 方编辑 2022

The following might help to illustrate the question.以下内容可能有助于说明问题。 Give there is only 1 <input type=range> in the html document this code shows if its children can be accessed.假设 html 文档中只有 1 个<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

The code above shows that the internals of an <input type=range> can not be accessed.上面的代码表明<input type=range>的内部不能被访问。

input_type_range_shadowRoot_access

Here is an example:这是一个例子:

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);

Demo:演示:

 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>

I hope this will help you.我希望这能帮到您。

To answer (a generalized version of) the OP question:要回答(广义版本)OP 问题:

How can you query elements, no matter if in shadowRoot or not?无论是否在 shadowRoot 中,如何查询元素?

It feels like the shadow root API is still lacking (or I just don't know it well enough).感觉好像仍然缺少影子根 API(或者我只是不太了解它)。 But it basically renders querySelectorAll somewhat useless, in that querySelectorAll will not actually get all matching elements anymore, since it simply ignores all ancestors in shadowRoots .但它基本上使querySelectorAll有点无用,因为querySelectorAll实际上不会再获得所有匹配的元素,因为它只是忽略了shadowRoots中的所有祖先。 Maybe there is an API that fixes that, but just in case there is not:也许有一个 API 可以解决这个问题,但以防万一:

Here is a simple function that recursively iterates all shadowRoots and gets you all matching elements on the page, not just those of a single shadowRoot .这是一个简单的函数,它递归地迭代所有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://stackoverflow.com/a/71692555/2228771
 */
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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM