什么是影子 DOM?
Scrapeless Scraping Browser 提供受管理的 Chromium 会话,用于自动化现代网页组件,包括使用开放的 Shadow DOM 树构建的接口。
TL;DR
- Shadow DOM 将一个封装的节点树附加到宿主元素。 影子树参与渲染,但与文档树有边界。
- 样式规则被限制在影子边界内。 页面CSS无法随意选择内部节点,内部CSS无法随意向外泄漏。
- 插槽项目轻量级 DOM 子元素到组件定义的位置。 节点保持在轻量DOM中,而它们的渲染位置遵循阴影树。
- 开放和封闭的根改变了JavaScript的可发现性。 开放的根通过 shadowRoot 暴露;闭合的根不会通过该属性返回。
- 自动化必须有意地穿越阴影边界。 文档级选择器的行为并不像递归搜索每个阴影树那样。
为什么组件边界很重要
Shadow DOM 影响浏览器如何暴露状态、渲染内容或决定何时自动操作是安全的。明确的定义防止团队将狭窄的信号视为普遍答案。这也使得测试失败更容易诊断,因为预期的浏览器行为与文档生命周期、API 或系统边界相关联。
对于网页自动化,实际问题总是比“页面准备好了吗?”或“浏览器看起来真实吗?”要狭窄得多。下一步可能需要启用一个控件,等待一个框架完成导航,附加一个组件的内部树,或保持一个渲染表面的连贯性。以下部分将该概念转化为可观察的检查,而不是依赖于民间传说。
影子 DOM 定义
Shadow DOM 是一种 Web 平台机制,允许一个元素托管一个带有作用域样式和封装实现细节的独立 DOM 树。主机留在文档的普通树中,通常称为光 DOM。附加的树以 ShadowRoot 开始,并包含组件的内部元素。
规则: 1. 仅输出翻译文本 - 无需解释,无需额外的封装代码块。 2. 精确保留Markdown/HTML结构(标题、列表、链接、表格)。 3. 保留任何占位符标记,如@@CODEBLOCK_0@@或@@INLINECODE_0@@,完全保持不变;绝不翻译、重新排序、合并或重新格式化它们。 4. 不得添加或删除```代码块,且不得将普通文本包装成代码块。 The MDN 阴影 DOM 指南 描述主机、影子树、影子边界和影子根。浏览器长期以来一直使用内部树来控制诸如媒体元素等。Web 组件 API 为网站作者提供了一种相关的封装模型。
阴影并不意味着不可见。内部节点可以在屏幕上渲染,接收事件,包含可访问的文本,并参与布局。边界改变了选择器、样式规则、事件路径和DOM访问的工作方式。这是一个工程边界,而不是信息保密的保证。
主机、根和树
阴影宿主是与阴影根连接的普通元素。ShadowRoot是锚定内部树的文档片段。组件可以创建一个开放根,这由宿主的shadowRoot属性返回,或者创建一个封闭根,该属性对外部代码返回null。
开放与关闭是API访问的选择,而不是安全边界。创建闭合根的代码可以保留自己的引用,浏览器调试工具可能会暴露内部结构。敏感数据不应放置在组件中,以为关闭模式使其保密。
规则: 1. 仅输出翻译文本——不进行解释,不添加额外的代码块。 2. 完全保留Markdown/HTML结构(标题、列表、链接、表格)。 3. 保持任何占位符令牌如@@CODEBLOCK_0@@或@@INLINECODE_0@@完全不变;绝不翻译、重排序、合并或重新格式化它们。 4. 不得添加或删除```代码块,也不得将普通文本包裹到代码块中。 WHATWG DOM标准阴影树模型 定义树根、主机关系、事件路径和重定向行为。这些规则解释了为什么从内部按钮发起的事件可以在组件外部观察到,并且其目标被重定向到主机。
样式封装
文档中的普通选择器不会深入影子内部。一个组件可以定义内部类名而不会与不相关的页面类发生冲突。内部样式规则也限于影子树,这防止了可重用组件意外地重新样式化周围的文档。
边界并非绝对隔离。诸如颜色和字体等继承属性可以从宿主流出。组件可以通过自定义属性和部分暴露意图样式钩子。伪类和伪元素为组件作者和消费者提供了控制样式协调的方式,而无需暴露每个内部选择器。
该模型提高了可维护性,但可能会导致测试代码出现意外情况。在组件迁移之前有效的选择器可能会因为控件移动到阴影根后而无法再找到相同的可见控件。修复方法是选择主机,进入受支持的阴影树,然后找到内部控件,或者使用显式支持阴影遍历的自动化定位器。
槽和组合树
插槽标记了光DOM子元素应该出现在组件呈现结构中的位置。提供的节点仍然是光DOM中主机的子节点。插槽分配会改变它在组合渲染树中的位置,组合渲染树是用户在光与阴影树合并后所感知的结构。
命名插槽让组件可以放置不同类别的内容,例如标题、图标和操作区域。默认插槽接收没有匹配插槽名称的节点。当没有节点被分配时,组件可以提供后备内容。
自动化必须区分所有权和视觉位置。插槽按钮可能作为一个轻量级 DOM 子项出现,即使它看起来在组件内部。内部阴影按钮需要阴影遍历。检查实时 DOM 和插槽分配可以防止不必要的深度选择器。
影子DOM和自定义元素
自定义元素和影子DOM是互补但独立的。 HTML 自定义元素规范 定义了作者如何注册新的元素名称和生命周期回调。自定义元素可以附加一个影子根,渲染仅轻量 DOM,或结合这两种方法。
生命周期时机很重要。一个主机可以在解析的文档中存在于其自定义元素定义加载之前,以及在其影子树附加之前。立即搜索内部内容的自动化可能会运行得太早。请等待组件被定义、影子根存在(在打开的情况下)以及其中的目标状态。
声明性 Shadow DOM 允许兼容的浏览器将模板解析为阴影根,而无需等待客户端构建。它支持服务器渲染的组件内部,并且可以改善首次渲染。测试代码仍应针对最终组件合约,而不是假设根是以声明性还是命令式方式创建的。
跨越阴影边界的可靠自动化
优先选择角色、标签、名称和组件级别的合同,而不是脆弱的内部类链。许多自动化库可以穿透影子根以支持定位器策略,但行为各异。记录选择器是否跨越影子边界,并避免假设普通CSS选择器是递归全局的。
闭合的根需要不同的策略。使用公共组件接口、可访问的语义、轻量级DOM控制或应用程序团队的合作。注入补丁以强制每个根公开会改变待测试的应用程序,并可能掩盖真实的集成问题。将闭合的内部视为实现细节,除非测试有明确的诊断原因去检查它们。
为了调试,请捕获主机选择器、根模式、组件定义状态、相关插槽和目标的可访问名称。检查事件是否在边界处被重新目标化。如果点击失败,请验证可见性、命中测试、覆盖层和组件状态,而不仅仅是添加更深的选择器。
选择稳定组件合约
从可以证明任务可以继续的最小条件或配置开始。保持标准兼容的浏览器行为,然后仅在工作流程需要时添加配置文件控制。记录浏览器版本和相关状态,以便后续差异可以得到解释。可重复的观察比简单声称一个页面、框架、显示或指纹只是“完成”或“安全”的广泛说法更有用。
- 定义下一个行动。 在等待或配置步骤之后,脚本或用户需要准确地执行以下操作。
- 选择一个可观察的信号。 更喜欢一个直接支持该操作的浏览器属性、生命周期状态、元素条件或渲染结果。
- 请提供需要翻译的文本。 浏览器、操作系统、屏幕、区域设置、图形和会话设置应描述一个合理的环境。
- 验证正常的应用程序行为。 隐私或自动化干预不应悄悄破坏其更改的API或组件。
- 捕获诊断证据。 在检查失败时保存相关的 URL、状态、控制台消息和配置名称。
结论
Shadow DOM 为组件提供了一个作用域内部树,同时保留了它们在更大文档和可访问性模型中的位置。主机、根、插槽、样式作用域和事件重新定位构成了基本的心理模型。当自动化明确处理边界,优先考虑公共组件语义,并等待组件定义和状态,而不是依赖于文档级 CSS 选择器时,自动化才能成功。
规则: 1. 仅输出翻译文本 — 不进行解释,不添加额外的代码围栏。 2. 精确保留Markdown/HTML结构(标题、列表、链接、表格)。 3. 将任何占位符令牌如@@CODEBLOCK_0@@或@@INLINECODE_0@@保持完全不变;绝对不要翻译、重新排序、合并或重新格式化它们。 4. 不要添加或删除```代码围栏,也不要将普通文本包裹在代码块中。 The Scrapeless Scraping 浏览器文档 解释了如何配置托管浏览器会话,而 抓取浏览器产品概述 描述浏览器自动化表面。这些资源为在授权工作流中应用该概念提供了产品背景。
准备好自动化现代网页组件了吗?
将浏览器渲染、会话配置和自动化基础设施移入受管的Chromium环境。
今天注册并获得 $5的免费积分 — 不需要信用卡.
领取您的 $5 信用 →常见问题解答
Shadow DOM 和 iframe 是一样的吗?
不。Shadow DOM 在同一文档和 JavaScript 领域内创建一个封装的树,而 iframe 嵌入一个独立的文档和浏览上下文。
一个封闭的阴影根是安全的吗?
不。关闭模式通过 host.shadowRoot 属性限制访问,但它不是保密或授权边界。
页面的 CSS 样式节点可以在 Shadow DOM 内部使用吗?
普通的页面选择器不跨越边界,尽管继承属性、自定义属性、部分和其他显式钩子可以影响组件样式。
为什么普通选择器会漏掉可见的阴影元素?
可见节点可能生活在一个单独的影子树中,因此自动化必须遍历打开的影子根,或使用支持影子边界的定位引擎。