Shadow DOM是Web Components的关键部分,它允许您使用与主DOM隔离的DOM元素子树创建基于组件的应用程序。
我想为元素创建一个影子 DOM,这样我就可以显示 Chrome 扩展的元素,而不会受到页面样式的影响。 当我查看 Element.createShadowRoo 的文档时...
我有一个 Angular Web 组件,是在 @Angular/elements 的帮助下构建的。 该 Web 组件已经在我的网站上运行了几个月,因此大部分代码、部署和加载都没有问题。 该项目...
使用 Chrome 扩展覆盖 Element.prototype.attachShadow
我需要访问具有封闭 Shadow DOM 的 Web 组件的 DOM,以进行某些 Selenium 测试。我在几篇参考文献中读到,您可以覆盖文档上的 Element.prototype.attachShadow...
发现 javascript 错误:无法读取 null 的属性(读取“shadowRoot”)
我正在尝试使用 python 进行网页抓取,但发现错误 JavascriptException:javascript错误:无法读取 null 的属性(读取“shadowRoot”) 我不明白如何解决它。 请...
现在 @property 最近随 Firefox 128 一起发布,我认为尝试一下是个好主意。 使用常规 HTML 和 CSS 时效果很好 @属性--a1 { 语法:' 现在 @property 最近随 Firefox 128 一起发布,我认为尝试一下是个好主意。 使用常规 HTML 和 CSS 时效果很好 @property --a1 { syntax: '<angle>'; inherits: false; initial-value: 10deg; } .hi1 { border: 2px solid black; width: fit-content; margin: 0 auto; } .box1 { --a1:10deg; /* needed for firefox to have a valid output */ cursor:pointer; width:250px; height:200px; margin:15px; display:inline-block; transition:--a1 0.5s; background:linear-gradient(var(--a1),red ,blue); } .box1:hover { --a1:180deg; } body { text-align:center; } <div class="hi1"> <h1>In regular DOM</h1> <div class="box1"></div> <div class="box1" style="background:conic-gradient(from var(--a1), red var(--a1),blue)"></div> <div class="box1" style="background:linear-gradient(calc(180deg - var(--a1)),red ,blue,red )"></div> </div> 但是如果我在影子 DOM 中使用它,它会突然被完全忽略。 const css = `@property --a2 { syntax: '<angle>'; inherits: false; initial-value: 10deg; } .hi2 { border: 2px solid black; width: fit-content; margin: 0 auto; } .box2 { --a2:10deg; /* needed for firefox to have a valid output */ cursor:pointer; width:250px; height:200px; margin:15px; display:inline-block; transition:--a2 0.5s; background:linear-gradient(var(--a2),red ,blue); } .box2:hover { --a2:180deg; }`; class MyComponent extends HTMLElement { constructor() { super(); const root = this.attachShadow({ mode: 'closed' }); root.innerHTML = ` <style>${css}</style> <div class="hi2"> <h1>In shadow DOM</h1> <div class="box2"></div> <div class="box2" style="background:conic-gradient(from var(--a2), red var(--a2),blue)"></div> <div class="box2" style="background:linear-gradient(calc(180deg - var(--a2)),red ,blue,red )"></div> </div>`; } connectedCallback() { } } customElements.define('my-component', MyComponent); <my-component> </my-component> 知道为什么或如何说服它起作用吗? 这是说明问题的 codepen https://codepen.io/true-cc/pen/eYwYJaM 这似乎应该可行,但由于没有浏览器支持它,我猜这是一个规格错误。规格中有这一段: 与 CSS 中的许多概念不同(请参阅CSS 范围 1 §3.5 名称定义构造和继承),属性注册的范围不限于树范围。所有注册,无论它们出现在最外层文档中还是出现在影子树中,都在Document的单个全局注册映射中进行交互。 为什么无法确定注册范围? 当自定义属性作为 Shadow DOM 使用组件的公共 API 的一部分公开时,此全局注册行为将按预期工作。如果外部页面出于不同目的使用同名的自定义属性,那么这已经是需要解决的冲突,并且注册行为不会使情况变得更糟。 但是,如果自定义属性旨在供组件内部私有使用,则建议为该属性指定一个可能唯一的名称,以尽量减少与任何其他上下文发生冲突的可能性。例如,可以通过在属性名称中包含项目名称或一些简短的随机文本字符串来完成。 这说明的是,由于 @property 只是调用全局 CSS.registerProperty() 方法的另一种方式,如果您在 Shadow DOM 中定义这样的规则,它仍然会影响 light DOM,因为只有一个注册表. 但是,没有浏览器支持 Shadow DOM 内的规则,它们都会完全忽略它。 因此,您可以全局声明该规则,或使用 CSS.registerProperty(),即使浏览器支持定义,如果影子 DOM 无论如何也不会被限定在所述影子 DOM 范围内。 使用全局规则: const css = ` .hi2 { border: 2px solid black; width: fit-content; margin: 0 auto; } .box2 { --a2:10deg; /* needed for firefox to have a valid output */ cursor:pointer; width:250px; height:200px; margin:15px; display:inline-block; transition:--a2 0.5s; background:linear-gradient(var(--a2),red ,blue); } .box2:hover { --a2:180deg; }`; class MyComponent extends HTMLElement { constructor() { super(); const root = this.attachShadow({ mode: 'closed' }); root.innerHTML = ` <style>${css}</style> <div class="hi2"> <h1>In shadow DOM</h1> <div class="box2"></div> <div class="box2" style="background:conic-gradient(from var(--a2), red var(--a2),blue)"></div> <div class="box2" style="background:linear-gradient(calc(180deg - var(--a2)),red ,blue,red )"></div> </div>`; } connectedCallback() { } } customElements.define('my-component', MyComponent); @property --a2 { syntax: '<angle>'; inherits: false; initial-value: 10deg; } <my-component> </my-component> 使用CSS.registerProperty(): const css = ` .hi2 { border: 2px solid black; width: fit-content; margin: 0 auto; } .box2 { --a2:10deg; /* needed for firefox to have a valid output */ cursor:pointer; width:250px; height:200px; margin:15px; display:inline-block; transition:--a2 0.5s; background:linear-gradient(var(--a2),red ,blue); } .box2:hover { --a2:180deg; }`; class MyComponent extends HTMLElement { constructor() { super(); const root = this.attachShadow({ mode: 'closed' }); root.innerHTML = ` <style>${css}</style> <div class="hi2"> <h1>In shadow DOM</h1> <div class="box2"></div> <div class="box2" style="background:conic-gradient(from var(--a2), red var(--a2),blue)"></div> <div class="box2" style="background:linear-gradient(calc(180deg - var(--a2)),red ,blue,red )"></div> </div>`; CSS.registerProperty({ name: "--a2", syntax: "<angle>", inherits: false, initialValue: "10deg", }); } connectedCallback() { } } customElements.define('my-component', MyComponent); @property --a2 { syntax: '<angle>'; inherits: false; initial-value: 10deg; } <my-component> </my-component>
使用 Python Selenium Geckodriver 的 Shadow DOM
我正在尝试使用此代码访问以下网站上的影子根元素 https://www.wego.ae/en/flights/searches/cSFO-cLHR-2020-03-09:cLHR-cSFO-2020- 03-22/经济/1a:0c:0i?sort=价格&订单...
假设我的文档中有一个如下所示的 DOM: #shadow-root(打开) 选择我 假设我的文档中有一个如下所示的 DOM: <body> <div id="outer"> <custom-web-component> #shadow-root (open) <div id="inner">Select Me</div> </custom-web-component> </div> </body> 是否可以使用 querySelector 上的单个 document 参数来选择影子根内的内部 div?如果有的话,它是如何构造的? 例如,类似document.querySelector('custom-web-component > #inner') 你可以这样做: document.querySelector("custom-web-component").shadowRoot.querySelector("#inner") 此代码的行为类似于 querySelector() 并可与嵌套 Shadow DOM 一起使用: function querySelector(selector) { return querySelectorAll(document, selector)[0]; } function querySelectorAll(node, selector) { const nodes = [...node.querySelectorAll(selector)]; const nodeIterator = document.createNodeIterator( node, NodeFilter.SHOW_ELEMENT, node => node instanceof Element && node.shadowRoot ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT, ); let currentNode = nodeIterator.nextNode(); while (currentNode) { nodes.push(...querySelectorAll(currentNode.shadowRoot, selector)); currentNode = nodeIterator.nextNode(); } return nodes; } 请注意,它不能保证与使用后代组合器的CSS选择器一起使用。 在上面的示例中,以下内容应该有效: querySelector('#inner') 它不能用单个选择器完成,该功能已从网络上删除:https://developer.chrome.com/blog/remove-shadow-piercing/ 但是您可以通过递归调用 querySelector 来完成。这可能很重,因此请根据您的情况使用最简单的版本。 如果您已经知道确切的根 document.querySelector(".your-root-selector") .shadowRoot.querySelector(".your-shadowed-selector") 如果你有很多根和很多阴影元素 这将循环遍历页面上的每个元素,因此它相当重。谨慎使用: const elements = [] for (const {shadowRoot} of document.querySelectorAll("*")) { if (shadowRoot) { elements.push(...shadowRoot.querySelectorAll(".your-shadowed-selector")); } } 如果你有嵌套的根 这会递归运行,很少使用: const elements = [] function findElements(root) { for (const {shadowRoot} of root.querySelectorAll("*")) { if (shadowRoot) { // Look for elements in the current root elements.push(...shadowRoot.querySelectorAll(".your-shadowed-selector")); // Look for more roots in the current root findElements(shadowRoot); } } } findElements(document); 简而言之,不完全是。 TL:DR 是,根据组件的设置方式,您可能可以执行以下操作: document.querySelector('custom-web-component').div.innerHTML = 'Hello world!'; 执行此操作 - 如果您有权访问创建 Web 组件的位置,则可以在其中添加一个接口来访问内部内容。您可以像公开任何 JavaScript 类变量/方法一样执行此操作。比如: /** * Example web component */ class MyComponent extends HTMLElement { constructor() { super(); // Create shadow DOM this._shadowRoot = this.attachShadow({mode: 'open'}); // Create mock div - this will be directly accessible from outside the component this.div = document.createElement('div'); // And this span will not let span = document.createElement('span'); // Append div and span to shadowRoot this._shadowRoot.appendChild(span); this._shadowRoot.appendChild(this.div); } } // Register component window.customElements.define('custom-web-component', MyComponent); // You can now access the component 'div' from outside of a web component, like so: (function() { let component = document.querySelector('custom-web-component'); // Edit div component.div.innerHTML = 'EDITED'; // Edit span component._shadowRoot.querySelector('span').innerHTML = 'EDITED 2'; })(); <custom-web-component></custom-web-component> 在这种情况下,您可以从组件外部访问 div,但无法访问 span。 补充:由于 Web 组件是封装的,我认为您无法选择组件的内部部分 - 您必须使用 this 显式设置选择它们的方式,如上所述。 编辑: 也就是说,如果你知道影子根键是什么,你可以这样做:component._shadowRoot.querySelector()(添加到上面的演示中)。但这是一件很奇怪的事情,因为它有点违背封装的想法。 编辑2 上述方法仅在使用 this 关键字设置影子根时才有效。如果影子根设置为 let shadowRoot = this.attachShadow({mode: 'open'}) 那么我认为您将无法搜索 span - 但那里可能是错误的。
如何获取包含shadowRoot元素的文档或节点中的所有HTML
这个问题我还没有看到满意的答案。这基本上是这个问题的重复,但它关闭不当并且给出的答案不充分。 我已经想出了自己的
使用 Selenium 访问封闭影子根中的 Iframe 内的 HTML 内容
我目前正在运营一个网站,该网站包含一个具有本机封闭影子根的 Web 组件。该 Web 组件在其结构中包含一个 iframe。我的目标是利用 Seleniu...
无法使用 Selenium 和 Python 在 #shadow-root (open) 中找到登录元素
我正在尝试使用 selenium 来自动执行某些操作,但无法找到页面 https://developer.servicenow.com/dev.do 上的第一个元素,因此无法登录 从硒导入网络驱动程序 来自
如何在 Selenium 中定位 Shadow DOM 和 iframe 内的元素并与之交互?
我正在尝试抓取一个具有 Shadow DOM 和 iframe 的网站。正如您在图片中看到的,我找不到 Shadow DOM 的任何选择器,因此我可以访问 iframe。 HTML 元素 我如何找到Shado...
所以我在一家公司工作。作为暑期实习生,并负责为他们在 cypress 中的应用程序编写测试。 该应用程序广泛使用shadow DOM,甚至嵌套shadow DOM。我用过...
如何从子影子 DOM 节点中提取 HTML 客户端,同时在其中包含其他影子根元素?
根据问题,应该如何从封装的影子 DOM 节点(还包含进一步嵌套的子影子节点)中完全提取客户端 HTML 代码? 供参考:...
如何使用 Angular 更改 Shadow DOM 中嵌套子元素的样式
我想更改包装在父元素内部的子元素的字体样式,该父元素在内部被其他元素包装,最后它被包含在影子根内。附加 DOM ...
RoosterJS 编辑器无法在 Shadow DOM 中工作
我正在尝试将 RoosterJS 富文本编辑器集成到 Shadow DOM 组件中,但它似乎无法正常工作。编辑器初始化,但格式化功能如粗体、斜体和bul...
我正在使用自定义 StencilJS 自定义组件,特别是 my-select 和 my-input,它们经常在 中一起使用。然而,有...
如何手动设置 Shadow DOM(Lit Web Component)中元素的焦点
我正在构建一个选择/下拉组件作为 Lit Web 组件。为了具有一致的样式,这不使用本机选择。我正在使用 div 并添加逻辑,让它们出现在何时何地
如何在 ion-toast(嵌套阴影元素)内设置离子图标的样式?
我尝试了多种方法: 设置内联样式,但看起来 @ionic 在生成 toast 时删除了 style="...." 属性 CSS 变量,但不知道如何设计新的样式...
我想始终显示输入“数字”字段的向上/向下箭头。这可能吗?到目前为止我还没有运气... http://jsfiddle.net/oneeezy/qunbnL6u/ HTML: CSS:
Angular Shadow Dom 组件中的 Cypress 组件测试
我正在尝试在 Angular 组件库上运行 Cypress 组件测试。目前,我的所有组件都打开了shadowDom。这似乎在运行多个时给我带来了问题