如何使用 JavaScript 获取用户代理影子根中的元素?
How to get element in user-agent shadow root with JavaScript?
我需要从 Shadow DOM 中获取元素并进行更改。我该怎么做?
<div>
<input type="range" min="100 $" max="3000 $">
</div>
这是一个例子:
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>
希望对您有所帮助。
您无法访问浏览器创建的 Shadow DOM 来显示控件,在 Dev Tools 中称为 #shadow-root (user-agent)
。 <input>
是一个例子。
您只能使用 { mode: 'open' }
选项访问 open 自定义影子 DOM(您自己创建的影子)。
element.attachShadow( { mode: 'open' } )
更新
大多数 UX 标准 HTML 元素都是如此:<input>
、<video>
、<textarea>
、<select>
、<audio>
等。
回答 OP 问题的(通用版本):
无论是否在 shadowRoot 中,如何查询元素?
感觉shadow root API 还是欠缺(或者是自己不太了解)。但它基本上使 querySelectorAll
有点无用,因为 querySelectorAll
实际上不再获得 all 匹配元素,因为它只是忽略了 shadowRoots
中的所有祖先.也许有一个 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
*/
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
我需要从 Shadow DOM 中获取元素并进行更改。我该怎么做?
<div>
<input type="range" min="100 $" max="3000 $">
</div>
这是一个例子:
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>
希望对您有所帮助。
您无法访问浏览器创建的 Shadow DOM 来显示控件,在 Dev Tools 中称为 #shadow-root (user-agent)
。 <input>
是一个例子。
您只能使用 { mode: 'open' }
选项访问 open 自定义影子 DOM(您自己创建的影子)。
element.attachShadow( { mode: 'open' } )
更新
大多数 UX 标准 HTML 元素都是如此:<input>
、<video>
、<textarea>
、<select>
、<audio>
等。
回答 OP 问题的(通用版本):
无论是否在 shadowRoot 中,如何查询元素?
感觉shadow root API 还是欠缺(或者是自己不太了解)。但它基本上使 querySelectorAll
有点无用,因为 querySelectorAll
实际上不再获得 all 匹配元素,因为它只是忽略了 shadowRoots
中的所有祖先.也许有一个 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
*/
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