测试【免费下载链接】axe-coreAccessibility engine for automated Web UI testing项目地址https://gitcode.com/gh_mirrors/ax/axe-core点击查看免费下载本文基于 axe-core 仓库的 doc/element-internals.md 编写深入讲解 axe-core 如何通过社区协议读取自定义元素CustomElement的 ElementInternals 信息、这些信息如何进入虚拟节点与规则判定流程以及当前支持范围与已知限制。读完本文你将掌握在自己的自定义元素上暴露 ElementInternals 的正确写法、axe-core 底层查找这些信息的完整顺序与守卫逻辑以及当 axe-core 运行在隔离 JS 上下文时如何通过axe.externalAPIs把收集到的数据交给引擎。背景为什么 axe-core 需要社区协议Web Components 生态中自定义元素可以通过attachInternals()获得一个ElementInternals对象并借此声明 ARIA 语义如role与表单行为如labels、form这就是所谓的ARIA Properties。例如一个自定义按钮组件可以这样声明自己是rolebuttonconst internals this.attachInternals(); internals.role button;问题在于JavaScript 并不提供任何公开 API 来从一个节点反向读取它的 ElementInternals 对象。浏览器把这份信息私有保存axe-core 作为第三方无障碍检测引擎在扫描 DOM 时无法凭空得知某个自定义元素内部声明了怎样的role。因此 axe-core 必须依赖开发者在其自定义元素上实现一种社区协议——即通过约定俗成的全局映射表或公开属性主动把ElementInternals暴露出来供 axe-core 查找。axe-core 本身不做任何假设只负责按协议去取。axe-core 支持的 ElementInternals 暴露协议根据 get-element-internals.js 源码 中的注释axe-core 目前支持以下两种方式、共六种取法方式一全局 WeakMapglobalThis._elementInternals开发者维护一个全局WeakMap以元素节点为键、以ElementInternals对象为值globalThis._elementInternals ?? new WeakMap(); globalThis._elementInternals.set(this, internals);axe-core 通过globalThis._elementInternals?.get(node)直接命中查找。这是官方文档给出的首选示例因为WeakMap以对象为键不会造成内存泄漏全局单例语义清晰一个页面只维护一份映射查找成本是 O(1)且不污染元素自身属性。方式二元素上的公开属性或 Symbol除了全局映射axe-core 还支持直接在自定义元素实例上挂载以下公共属性public properties或 Symbol暴露形式类型源码常量get-element-internals.js_internals字符串属性propNames[0]internals字符串属性propNames[1]internals_字符串属性propNames[2]Symbol(internals)SymbolsymbolNames[0]Symbol(privateInternals)SymbolsymbolNames[1]文档给出的推荐写法是_internals官方注释标记为recommended因为它直观、不易与既有框架属性冲突且避免了全局状态的污染CustomElements.define( my-custom-button, class MyCustomButton extends HTMLElement { constructor() { super(); this._internals this.attachInternals(); this._internals.role button; } } );其中Symbol(internals)与Symbol(privateInternals)适合想要隐藏实现细节、防止被普通属性枚举或误读的组件库作者。源码级解析getElementInternals 的查找顺序与守卫axe-core 的入口工具函数位于 lib/core/utils/get-element-internals.js它会按严格的顺序执行查找并带有多重安全守卫export default function getElementInternals(node) { // 1. 只有合法自定义元素名才继续 if (!isValidCustomElementName(node.nodeName.toLowerCase())) { return; } // 2. 优先查全局 WeakMap const mapInternals globalThis._elementInternals?.get(node); if (mapInternals) { return mapInternals; } // 3. IE11 守卫环境不支持 ElementInternals 直接放弃 if (!(ElementInternals in window)) { return; } // 4. 依次检查三个字符串属性 for (const propName of propNames) { if (Object.getOwnPropertyDescriptor(node, propName)?.get) { continue; // 跳过 getter 定义的属性 } if (node[propName] instanceof window.ElementInternals) { return node[propName]; } } // 5. 检查两个 Symbol 属性 const ownSymbols Object.getOwnPropertySymbols(node); for (const symbolName of symbolNames) { const symbol ownSymbols.find(s s.description symbolName); if (symbol) { if (Object.getOwnPropertyDescriptor(node, symbol)?.get) { continue; } if (node[symbol] instanceof window.ElementInternals) { return node[symbol]; } } } }几个值得注意的实现细节自定义元素名校验attachInternals()只能作用于自定义元素对原生元素或 customized built-in如button is...调用会抛错。源码通过isValidCustomElementName提前拦截避免后续逻辑对非法节点误判。测试 test/core/utils/get-element-internals.js 专门覆盖了原生元素与customized built-in 元素两种必须返回undefined的场景。getter 守卫如果属性是Object.defineProperty定义的 getter而非数据属性axe-core 会跳过它。原因getter 可能在取值时产生副作用或抛错且社区协议约定的是直接赋值读取 getter 不可靠。对应测试见 test/core/utils/get-element-internals.js。类型校验属性值必须是window.ElementInternals的实例才会被接受防止开发者误把任意字符串或对象当作 internals 传入测试见 test/core/utils/get-element-internals.js。全局映射优先当元素同时出现在全局 WeakMap 和自身属性上时以全局映射为准测试见 test/core/utils/get-element-internals.js若全局映射中不存在该节点则回退到属性查找test/core/utils/get-element-internals.js。跨属性容错如果_internals是 getter 被跳过但internals是正常数据属性依然能取到test/core/utils/get-element-internals.js。数据如何进入 axe-corewalkTree 收集与虚拟节点挂载找到ElementInternals只是第一步。axe-core 在扫描页面时由 lib/gather-internals/walk-tree.js 的walkTree()完成收集使用document.createTreeWalker遍历整棵 DOM对每个元素调用getElementInternals(node)命中后记录该节点的ancestryCSS 祖先选择器由getAncestry生成用于跨上下文唯一定位节点遍历ElementInternals的可枚举属性只保留两类以aria[A-Z]开头的 ARIA 属性正则ariaPropRegex /^aria[A-Z]/如ariaLabel、ariaLabelledByElements、ariaActiveDescendantElement等白名单propsToCapture [role, labels, form]。把结果推入elementInternalsMap数组每条形如{ ancestry, internals }。对 idref / idrefs 类属性例如ariaActiveDescendantElement指向某个元素、ariaLabelledByElements指向一组元素walkTree 会把DOM 节点引用转换为 ancestry 字符串并在节点未连接到文档树时直接丢弃见 walk-tree.js 及测试 test/gather-internals/index.js。读取internals.form时若元素不是表单关联元素会抛错源码用 try/catch 静默吞掉walk-tree.js。收集完成后axe-core 在构建虚拟节点时把数据挂到 vNode 上。VirtualNode提供了带缓存的elementInternalsgetterlib/core/base/virtual-node/virtual-node.js后续所有规则与 commons 逻辑都通过vNode.elementInternals访问。规则如何消费 roleimplicitRole 与匹配器ElementInternals 的role最终参与角色计算。在 lib/commons/aria/implicit-role.js 中if (vNode.elementInternals?.role) { return vNode.elementInternals.role; }即当自定义元素通过 ElementInternals 声明了role时该 role 优先于元素名称推导出的隐式角色。同理lib/commons/matches/in-sectioning-content.js 在判断元素是否位于分区内容landmark 判定相关时也会读取elementInternals?.role作为兜底角色来源。当前支持范围与已知限制务必阅读原文档明确标注了以下边界源码行为与之完全一致仅支持role属性。ariaLabel等其他 ElementInternals 属性目前不被规则消费尽管 walkTree 会捕获以aria开头的属性但当前规则体系主要依赖role更多属性的支持已在计划中。axe-core 不校验 ElementInternalsrole的值。即使传入非法角色名也不会触发aria-valid-attr-value之类的校验。许多规则不会在带 ElementInternals 的元素上运行。典型如aria-required-attr——因为 axe-core 无法获知完整的 ARIA 状态选择直接跳过。部分规则只是部分支持。例如aria-required-children可能只能做有限判定。因此如果自定义元素完全依赖 ElementInternals 表达无障碍语义请意识到 axe-core 对它的覆盖是逐步扩展的不要期待与原生 HTML 元素同等的检测深度。进阶隔离 JS 上下文下的 externalAPIs 集成社区协议依赖开发者把 internals 暴露出来 axe-core 直接遍历 DOM。但在浏览器扩展等场景中axe-core 可能运行在隔离的 JS 上下文如扩展的 content script此时attachInternals的实例与 DOM 遍历都可能不可用。axe-core 为此提供了axe.externalAPIs({ elementInternals })入口lib/core/public/external-apis.js注册于 lib/core/core.jsaxe.externalAPIs({ elementInternals() { return Promise.resolve([ { // CSS ancestry 选择器可由 axe.utils.getAncestry(node) 生成 ancestry: html body main my-custom-button, internals: { role: button } } ]); } });elementInternals必须返回一个 Promiseresolve 出一个数组每个元素包含ancestry字符串或字符串数组用于 Shadow DOM 场景与internals对象属性值需自行序列化idref 类属性用{ type: HTMLElement, value: ancestry }或{ type: NodeList, value: [ancestry] }表达。同时可配置elementInternalsTimeout默认 1000ms。若 Promise 超时axe-core 将直接抛错external-apis.js。传入的数据会在loadElementInternals中经结构校验后通过shadowSelectgetNodeFromTree定位节点再反向把internals挂到对应 vNode 上external-apis.js。仓库还提供了可直接注入主上下文的收集脚本gather-internals.js构建产物源码即 lib/gather-internals/main.js在扩展中可用chrome.scripting.executeScript({ files: [gather-internals.js], world: MAIN })注入后把返回的elementInternalsMap数组直接作为 Promise 的 resolve 值。完整的配置说明见 doc/external-apis.md。验证与测试仓库为这套机制提供了完备的测试可作为你接入时的行为基准test/core/utils/get-element-internals.js覆盖全局映射、三种字符串属性、两种 Symbol、getter 跳过、类型校验、ElementInternals不存在守卫、原生元素与 customized built-in 拒绝等全部边界。test/gather-internals/index.js覆盖 walkTree 的收集结果结构、嵌套元素、Shadow DOM 内元素、ancestry 生成、idref/idrefs 解析与未连接节点丢弃、form与labels捕获以及无需 axe 环境也能运行的独立性验证。小结axe-core 对 CustomElement ElementInternals 的支持是一套约定优于配置的务实方案通过社区协议把浏览器不公开的私有状态显式暴露出来再用getElementInternals → walkTree → vNode.elementInternals → implicitRole/匹配器这条完整链路把role纳入规则判定。如果你在开发无障碍组件库建议优先采用_internals属性或全局 WeakMap 两种协议之一如果你的 axe-core 跑在隔离上下文则直接使用axe.externalAPIs({ elementInternals })传数据。同时牢记当前仅role受支持、值不校验、部分规则不运行的边界合理规划检测覆盖预期。赞分享测试【免费下载链接】axe-coreAccessibility engine for automated Web UI testing项目地址https://gitcode.com/gh_mirrors/ax/axe-core点击查看免费下载相关推荐gh_mirrors/core72/core社区指南贡献代码与获取支持gh_mirrors/core72/core社区指南贡献代码与获取支持 你是否在使用Online IDE时遇到问题不知如何反馈想为项目贡献代码却找不到入门路LocalSend WebRTC集成实时通信协议支持与实现LocalSend WebRTC集成实时通信协议支持与实现 引言为什么需要WebRTC 在现代分布式应用中实时通信Real time Communic即时通讯网络/通信A2A 协议社区全景指南生态集成、社区 SDK 与参与路径A2A 协议社区全景指南生态集成、社区 SDK 与参与路径 Agent2AgentA2A是一个开放、标准化的协议用于实现不同框架、不同厂商之间 AI 智人工智能AI AgentAPI设计上一篇Hermes Agent连接池参数怎么配4 个指标验证调优生效下一篇tModLoader模组热重载技术如何在不重启游戏的情况下测试模组创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
Notepad-- 跨平台文本编辑器:从安装到批量查找替换的完整指南 Notepad-- 跨平台文本编辑器:从安装到批量查找替换的完整指南 【免费下载链接】notepad-- 一个支持windows/linux/mac的文本编辑器,目标是做中国人自己的编辑器,来自中国。 项目地址: https://gitcode.com/GitHub_Trending/no/notepad-- … · 2026/9/28 2:56:07
GSD 的非技术用户设计指南:为「Vibe Coder」构建的意图翻译层与十根体验支柱 人工智能AI Agent代码智能体Agent 编排CLIAI 应用 【免费下载链接】gsd-2 A powerful meta-prompting, context engineering and spec-driven development system that enables agents to work for long periods of time autonomously without losing track of the big picture… · 2026/9/28 2:56:07
基于深度学习的人脸识别考勤系统全流程实战与避坑指南 简介:一份面向计算机专业毕业设计与考勤应用场景的完整Python源码项目,适合正在完成课程设计、期末大作业,或希望从项目实战中提升识别系统开发能力的学习者。项目基于深度学习完成人脸识别考勤的核心流程,压缩包共25个文件&#… · 2026/9/28 2:56:01
Spingboot启动预热的实现 启动预热的适用场景启动预热适合以下情况:数据主要来自第三方接口,无法直接从本地数据库读取。第三方接口响应较慢,首次访问容易超时。一个页面需要调用多个第三方接口或逐项查询。数据读取频繁,但变化不频繁。希望服务启动后&… · 2026/9/28 3:40:12
学Java别走弯路,这5个方向最吃香 学Java的人很多,但学明白的人不多。有人学了半年还在写控制台程序,有人一年就能独当一面。差别不在天赋,而在方向。Java生态太庞大了,什么都学等于什么都没学。选对方向,事半功倍。今天盘点当前最吃香的5个Java方向&am… · 2026/9/28 3:32:15
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
制作网页比较方便的软件怎么选?一文搞懂避坑指南 制作网页比较方便的软件怎么选?一文搞懂避坑指南 很多老板一上来就问:做个网站多少钱?但我反问他:你的域名买了吗?服务器租了吗?他一脸懵。这就是典型的“域名服务器搞不懂”。别急,今天咱们不聊虚的,直接 一文搞懂 那些让你头秃的技术名词。… · 2026/9/28 0:00:06
婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量 婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量 找婚恋网站建站公司,最怕的就是被坑高价。很多同行跟我吐槽,报价单上写得模棱两可,功能栏里全是“高级定制”、“专属UI”,结果落地全是套壳。今天不聊虚的,直接甩几个我经手的 实战案例… · 2026/9/28 0:00:19
济南做网站多少钱:3个案例拆解,防黑源码下载全攻略 济南做网站多少钱:3个案例拆解,防黑源码下载全攻略 上周济南一个做建材的老板找我,脸都绿了。他的官网首页弹出了赌博广告,后台被植入了挖矿脚本。他慌得问我:“网站被黑挂马不知道怎么办?能不能直接找之前的外包公司要源码下载,看看哪里被动了手脚?… · 2026/9/28 0:00:25