Web 无障碍工程化实战:VSCode 扩展 + AI 自动修复全解析
本文探讨了Web无障碍设计的工程化实践方案。通过分析一个存在无障碍问题的Web界面案例,指出常见缺陷如表结构不规范、对比度不足、焦点样式缺失等问题。文章介绍了WCAG(Web内容无障碍指南)标准,并总结了四大核心设计原则:1)确保足够对比度(4.54:1符合AA标准);2)为非文本内容提供替代文本;3)确保键盘可操作性和清晰焦点指示;4)表单元素需正确关联标签说明。最后提出通过开发VSCode扩展
Web 无障碍工程化实战:VSCode 扩展 + AI 自动修复全解析
在大型Web系统开发中,界面是否符合无障碍设计标准,直接影响着不同能力用户的使用体验。
然而在功能复杂、界面繁多的Web系统中,开发团队往往将重心集中在业务逻辑实现和功能完整性上,容易忽视界面的可访问性设计,导致特殊用户群体无法正常使用系统功能。
通过遵循无障碍设计原则,可以确保视觉障碍、听觉障碍、运动障碍等不同需求的用户都能平等地访问和使用Web应用。
本文将从理论到实践,全面阐述无障碍开发的核心概念与实施方案。首先介绍无障碍开发的基本理念和重要意义,然后解析WCAG等主流无障碍规范标准,梳理当前可用的无障碍检测和修复工具生态。最后,本文将通过实现一个功能完整的VSCode扩展插件,为Web开发人员提供集成化的无障碍开发辅助工具,帮助开发团队在日常编码过程中更好地识别和解决无障碍问题。
引言
WCAG(Web Content Accessibility Guidelines) 是由 W3C 的 WAI 组织制定的网络内容无障碍标准。这套指南主要为残障人士提供更好的网络访问体验,同时也能改善所有用户和设备(包括数字助理等受限设备)的使用体验。
目前 WCAG 2.2 是最新的正式版本,而 WCAG 2.1 和 2.0 仍在广泛使用中。
WCAG 3.0 还处于工作草案阶段。新版本并不会取代旧版本,但 WAI 建议开发者优先使用最新版本,以确保网站获得最佳的无障碍访问效果。
无障碍指南:https://www.w3.org/TR/WCAG21/
Web界面案例分析
下图是一个存在多个问题的Web界面和修复后的结果
从直观上看,左侧的web界面给人的印象是模糊混乱的,右侧的web界面给人的印象是简洁美观的。原因在于左侧的web界面没有考虑无障碍指南中提到的多个要点,下面我们将逐一分析界面存在的问题。
以下是左侧界面表格部分源码:
<h2>季度销售表</h2>
<table>
<tr>
<th>季度</th>
<th>销售额</th>
<th>区域</th>
</tr>
<tr>
<td>Q1</td>
<td>12000</td>
<td><a href="#">东部</a></td>
</tr>
<tr>
<td>Q2</td>
<td>15000</td>
<td><a href="#">西部</a></td>
</tr>
<tr>
<td>Q3</td>
<td>9000</td>
<td><a href="#">南部</a></td>
</tr>
<tr>
<td>Q4</td>
<td>20000</td>
<td><a href="#">北部</a></td>
</tr>
</table>
在设计表格时,由于缺少 标签,表格标题用
写在外面。也没有使用 和 区分表头和数据区域,这将导致屏幕阅读器无法将标题与表格关联。
当表格没有正确标记的表头时,屏幕阅读器只能逐个朗读单元格内容,用户听到的是一串没有上下文的数据,完全不知道每个数据代表什么意思。除此之外,表格的样式设计也存在问题,虽然使用了奇偶行颜色差异,但是色差较小,最终给人的直观印象不够清晰明了
tbody tr:nth-child(even) {
background: #FAFBFE;
}

修改后的代码如下:
<table>
<caption class="visually-hidden">2025 年各季度按区域的销售额(单位:元)</caption>
<thead>
<tr>
<th scope="col">季度</th>
<th scope="col">销售额</th>
<th scope="col">区域</th>
</tr>
</thead>
<tbody>
<tr>
<td>Q1</td>
<td>12000</td>
<td><a href="#">东部</a></td>
</tr>
<tr>
<td>Q2</td>
<td>15000</td>
<td><a href="#">西部</a></td>
</tr>
<tr>
<td>Q3</td>
<td>9000</td>
<td><a href="#">南部</a></td>
</tr>
<tr>
<td>Q4</td>
<td>20000</td>
<td><a href="#">北部</a></td>
</tr>
</tbody>
</table>
除此之外,对颜色也做了调整:
tbody tr:nth-child(even) {
background: #F5F8FF;
}
最终效果如下:

再来观察原界面的表单部分,输入框得到焦点后,样式设计也不够直观。

此外按钮的背景色和前景色的对比度也较小,不够清晰。
:focus {
outline: none;
box-shadow: 0 0 0 2px rgba(26, 115, 232, 0.25);
border-radius: 4px;
}
.btn {
display: inline-block;
background: #4A90E2;
color: #fff;
padding: 5px;
border: 0;
border-radius: 3px;
cursor: pointer;
}
让我们使用以下代码,修正表单样式,突出文本框得到焦点后的样式,让按钮的对比度更强烈
:focus-visible {
outline: 3px solid #1A73E8;
outline-offset: 2px;
}
.btn {
background: #2F6BC2;
color: #fff;
padding: 8px;
border: 0;
border-radius: 6px;
cursor: pointer;
}

修改之后的界面明显更清晰直观。
无障碍指南
基于以上分析,我们了解到web界面存在多种设计细节,每一处缺陷都可能让整个界面的用户体验大打折扣。
那么标准的无障碍指南都制定了那些规范呢?
让我们看看下总结的内容:
1)对比度达标
- 设计原则1:对比度达标
- 设计思路1:保证文字和背景有足够的对比度,用户能很容易分辨出页面的组件
- 代码分析1:
/* ❌ 对比度不足 */
.bad-contrast {
color: #999999;
background: #ffffff; /* 对比度约 2.85:1 */
}
/* ✅ 符合 AA 标准 */
.good-contrast {
color: #595959;
background: #ffffff; /* 对比度约 4.54:1 */
}
/* ✅ 符合 AAA 标准 */
.excellent-contrast {
color: #333333;
background: #ffffff; /* 对比度约 7.73:1 */
}
2)图片设置替代文本
- 设计原则2:图片设置替代文本
- 设计思路2:所有非文本内容提供合适的 alt,供读屏器朗读,辅助用户理解含义
- 代码分析2:
<!-- ✅ 描述图片传达的信息 -->
<img src="sales-chart.png" alt="2023年第四季度销售额增长25%">
<!-- ❌ 不设置alt属性 -->
<img src="sales-chart.png">
3)键盘无障碍
- 设计原则3:键盘无障碍
- 设计思路3:所有功能可用键盘操作,焦点顺序合理且样式清晰可见
- 代码分析3:
/* ✅ 清晰的焦点指示 */
button:focus {
outline: 2px solid #005fcc;
outline-offset: 2px;
}
/* ✅ 高对比度焦点样式 */
.custom-focus:focus {
box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.3);
border: 2px solid #005fcc;
}
/* ❌ 移除焦点样式 */
button:focus {
outline: none;
}
4)表单可理解
- 设计原则4:表单可理解
- 设计思路4:每个输入有
- 代码分析4:
<!-- ✅ 使用 fieldset 和 legend -->
<fieldset>
<legend>联系方式</legend>
<label for="phone">电话</label>
<input type="tel" id="phone">
<label for="email2">邮箱</label>
<input type="email" id="email2">
</fieldset>
<!-- ✅ 单选按钮组 -->
<fieldset>
<legend>选择付款方式</legend>
<input type="radio" id="credit" name="payment" value="credit">
<label for="credit">信用卡</label>
<input type="radio" id="paypal" name="payment" value="paypal">
<label for="paypal">PayPal</label>
</fieldset>
5)语义结构与原生优先
- 设计原则5:语义结构与原生优先
- 设计思路5:正确使用标题层级、列表、表格表头/范围;优先使用 / 等原生控件,而不是div代替
- 代码分析5:
<!-- ✅ 使用原生按钮 -->
<button type="button" onclick="submitForm()">提交</button>
<!-- ❌ 用 div 模拟按钮 -->
<div class="fake-button" onclick="submitForm()">提交</div>
<!-- ✅ 原生链接 -->
<a href="/products">查看产品</a>
<!-- ❌ 用其他标签模拟链接 -->
<span class="fake-link" onclick="location.href='/products'">查看产品</span>
6)响应式与可重排
- 设计原则6:响应式与可重排
- 设计思路6:在窄屏(如 320px)内容清晰可读、不需水平滚动/ 等原生控件,而不是div代替
- 代码分析6:
/* ✅ 相对单位确保可缩放 */
body {
font-size: 1rem; /* 16px */
line-height: 1.5;
}
h1 {
font-size: 2rem; /* 32px */
}
/* ✅ 在小屏幕上适当调整 */
@media (max-width: 320px) {
body {
font-size: 0.9rem;
}
h1 {
font-size: 1.75rem;
}
}
axe扫描器工具
除了上文详细介绍的各种无障碍界面设计原则,开发中我们可以借用扫描器工具,检查web界面是否存在问题。
axe DevTools 是由 Deque 开发的Chrome 浏览器扩展,专为开发者、测试人员和设计师打造的无障碍检测工具。它基于业界知名的 axe-core 引擎,能够快速、准确地发现并修复网站无障碍问题。
axe DevTools 安装地址:https://chromewebstore.google.com/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd
安装上述扩展后,可以按照如下步骤检测:
首先,打开开发者调试窗口:

找到新增的axe DevTools的tab标签,点击后即可打开axe 工具的界面
框选界面某个部分,即可开始检测。例如下图检测出表单存在一些问题:

VSCode 扩展实现界面无障碍检测
除了使用 axe DevTools工具,我们还可以使用其他工具进行检测
axe-core 是一个专为网站和 HTML 界面设计的无障碍测试引擎,支持 WCAG 2.0、2.1、2.2 各级别标准,具有快速、安全、轻量级的特点,能够无缝集成到现有测试环境中。
下面是一个简单的介绍:
首先安装 axe-core这个npm包:
npm install axe-core --save-dev
axe-core包提供了axe模块,该模块提供了一个run方法,运行之后可以检查出页面所有的无障碍问题,实现的JS代码如下:
axe
.run()
.then(results => {
if (results.violations.length) {
console.log('发现无障碍问题:', results.violations);
throw new Error('Accessibility issues found');
} else {
console.log('未发现无障碍问题!');
}
})
.catch(err => {
console.error('检测过程中出错:', err.message);
});
除此之外,我们还可以配置检测的具体规则,以及某条规则检测失败后,如何汇报警告消息
// 配置检测规则和级别
axe.configure({
branding: {
brand: "测试应用",
application: "accessibility-checker"
},
rules: {
// 禁用某些规则
'color-contrast': { enabled: false },
// 只检查 AA 级别
'wcag2aa': { enabled: true }
},
// 只运行指定标签的规则
tags: ['wcag2a', 'wcag2aa']
});
// 应用中文本地化
axe.configure({
locale: {
lang: 'zh',
rules: {
'missing-headings': {
help: '页面应该包含至少一个 h1 标题'
}
},
checks: {
'color-contrast': {
fail: '文本颜色与背景颜色对比度不足'
}
}
}
});
基于以上对axe的基本使用,我们可以创建一个vscode扩展用来在编写web界面时检测无障碍问题。
1 使用如下命令搭建环境:
npm install -g yo generator-code
Yeoman 是微软推荐的脚手架工具,它会为我们生成完整的扩展项目结构:
yo: Yeoman 命令行工具,用于运行代码生成器generator-code: 微软官方的 VSCode 扩展生成器,包含了扩展开发的最佳实践模板
生成的项目结构包含:
src/extension.ts: 扩展的主入口文件,包含activate和deactivate函数package.json: 扩展的清单文件,定义扩展的功能、命令、配置等tsconfig.json: TypeScript 编译配置.vscode/: 包含调试配置,让我们能够直接在 VSCode 中调试扩展
2 安装依赖包
运行如下命令
cd accessibility-checker
npm install axe-core jsdom
npm install --save-dev @types/vscode
axe-core- 一个纯 JavaScript 库,可以在任何 JavaScript 环境中运行
- 包含了 WCAG 2.0/2.1/2.2 的完整规则集,覆盖 A、AA、AAA 三个等级
jsdom: Node.js 环境下的 DOM 模拟器- 由于 axe-core 需要 DOM 环境才能运行,而 VSCode 扩展运行在 Node.js 中
- jsdom 创建一个完整的虚拟 DOM 环境,让我们能在后端运行前端代码
- 支持大部分 Web API,包括
document、window、Element等
@types/vscode: VSCode API 的 TypeScript 类型定义- 提供完整的 VSCode 扩展 API 类型提示
- 包含所有命令、事件、UI 组件的类型定义
- 让我们能够安全地使用 VSCode 的各种功能
3 创建 axe-core 扫描器
axe-core 原本设计在浏览器中运行,需要 DOM 环境,我们需要将浏览器环境下的 axe-core 移植到 VSCode 扩展的 Node.js 环境,将 axe-core 的检测结果映射到 VSCode 的诊断系统。
import * as vscode from "vscode";
// 定义数据结构 - 映射 axe-core 的返回结果
export interface AxeResults {
violations: AxeViolation[];
}
export interface AxeViolation {
id: string; // 规则ID,如 'missing-headings'
help: string; // 简短的帮助信息
description: string; // 详细的问题描述
nodes: AxeNode[]; // 有问题的 DOM 节点
}
export interface AxeNode {
html: string; // 节点的 HTML 源码
target: string[]; // CSS 选择器路径
failureSummary?: string; // 失败原因总结
}
export class AxeScanner {
async scanDocument(doc: vscode.TextDocument): Promise<AxeResults | null> {
const html = doc.getText();
try {
const { JSDOM } = await import("jsdom");
const axe = await import("axe-core");
// 创建虚拟 DOM 环境
const { document } = new JSDOM(html).window;
// 运行 axe-core 检测整个页面内容
const results = await axe.run(document.body as any, {
rules: {
"color-contrast": { enabled: false },
}
});
// 数据转换
// 将 axe-core 结果转换为VSCode中需要的数据结构
return {
violations: results.violations.map((v: any) => ({
id: v.id,
help: v.help,
description: v.description,
nodes: v.nodes.map((n: any) => ({
html: n.html,
target: n.target ?? [],
failureSummary: n.failureSummary,
}))
}))
};
} catch (error) {
console.error('扫描过程中发生错误:', error);
throw error;
}
}
}
4 实现扫描功能
import * as vscode from "vscode";
import { AxeScanner } from "./axe-scanner";
export async function performScan(
textEditor: vscode.TextEditor,
axeScanner: AxeScanner,
context: vscode.ExtensionContext
) {
const doc = textEditor.document;
vscode.window.showInformationMessage("开始检测无障碍问题...");
try {
// 使用上文中创建的 AxeScanner类进行无障碍检测
const results = await axeScanner.scanDocument(doc);
// 处理无问题的情况
if (!results?.violations.length) {
vscode.window.showInformationMessage("✅ 未发现无障碍问题!");
// 清除之前的诊断信息
const collection = vscode.languages.createDiagnosticCollection("accessibility-checker");
collection.set(doc.uri, []);
context.subscriptions.push(collection);
return;
}
// 转换检测结果为 VSCode 诊断格式
const diagnostics: vscode.Diagnostic[] = [];
for (const violation of results.violations) {
for (const node of violation.nodes) {
// 定位问题在源码中的位置
const range = findElementRange(doc, node.html);
// 创建诊断对象
const diagnostic = new vscode.Diagnostic(
range ?? new vscode.Range(0, 0, 0, 1), // 默认位置防止错误
`${violation.help}\n${violation.description}`, // 完整的问题描述
vscode.DiagnosticSeverity.Warning // 警告级别
);
// 添加错误代码和来源信息
diagnostic.code = violation.id;
diagnostic.source = 'accessibility-checker';
diagnostics.push(diagnostic);
}
}
// 将诊断信息注册到 VSCode 系统
const collection = vscode.languages.createDiagnosticCollection("accessibility-checker");
collection.set(doc.uri, diagnostics);
context.subscriptions.push(collection);
// 向用户报告检测结果
vscode.window.showWarningMessage(
`⚠️ 发现 ${results.violations.length} 个无障碍问题`,
'查看问题'
).then(selection => {
if (selection === '查看问题') {
vscode.commands.executeCommand('workbench.action.problems.focus');
}
});
} catch (error: any) {
// 错误处理 - 提供有意义的错误信息
vscode.window.showErrorMessage(`扫描失败: ${error.message}`);
console.error('扫描失败:', error);
}
}
// 源码定位算法
function findElementRange(doc: vscode.TextDocument, html: string): vscode.Range | undefined {
const text = doc.getText();
const index = text.indexOf(html);
if (index === -1) return undefined;
// 将字符索引转换为行列位置
const start = doc.positionAt(index);
const end = doc.positionAt(index + html.length);
return new vscode.Range(start, end);
}
5 在入口文件中注册扫描功能
export function activate(context: vscode.ExtensionContext) {
// 创建扫描器实例
const axeScanner = new AxeScanner();
// 注册扫描命令
const scanCommand = vscode.commands.registerTextEditorCommand(
"accessibility-checker.scan",
async (textEditor: vscode.TextEditor) => {
// 检查是否是 HTML 文件
if (textEditor.document.languageId !== 'html') {
vscode.window.showWarningMessage('此功能仅支持 HTML 文件');
return;
}
// 调用扫描函数
await performScan(textEditor, axeScanner, context);
}
);
// 将命令注册到扩展生命周期中
context.subscriptions.push(scanCommand);
// 可选:添加状态栏项
const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
statusBarItem.command = 'accessibility-checker.scan';
statusBarItem.text = '$(accessibility) A11Y';
statusBarItem.tooltip = '检查无障碍问题 (Ctrl+Alt+A)';
// 只在 HTML 文件中显示状态栏项
const updateStatusBar = () => {
const editor = vscode.window.activeTextEditor;
if (editor && editor.document.languageId === 'html') {
statusBarItem.show();
} else {
statusBarItem.hide();
}
};
// 监听编辑器切换事件
vscode.window.onDidChangeActiveTextEditor(updateStatusBar);
updateStatusBar(); // 初始化状态栏
context.subscriptions.push(statusBarItem);
}
6 在package.json中绑定步骤5的命令
"contributes": {
"commands": [
{
"command": "accessibility-checker.scan",
"title": "扫描无障碍问题",
"category": "无障碍检查",
"icon": "$(accessibility)"
}
],
"menus": {
"editor/context": [
{
"command": "accessibility-checker.scan",
"when": "resourceExtname == .html",
"group": "accessibility@1"
}
],
"commandPalette": [
{
"command": "accessibility-checker.scan",
"when": "editorLangId == html",
"title": "无障碍检查: 扫描当前文件"
}
],
"explorer/context": [
{
"command": "accessibility-checker.scan",
"when": "resourceExtname == .html",
"group": "accessibility@1"
}
]
},
"keybindings": [
{
"command": "accessibility-checker.scan",
"key": "ctrl+alt+a",
"mac": "cmd+alt+a",
"when": "editorLangId == html"
}
]
}
最终效果如下:
安装该扩展,打开html文件,在右键菜单中找到无障碍检测
点击该菜单项,启动无障碍检测

检测到该问题后,插件会在响应代码行处添加黄色波浪线
鼠标悬停在某一行,可以看到无障碍问题

AI赋能无障碍检测与修复
由于上述插件仅利用axe工具检测了无障碍问题,开发者需要逐一修复这些问题。
考虑到VSCode提供了AI大语言模型 API ,我们还可以实现了从"发现问题"到"自动解决"的完整闭环。
设计思路如下:
- 首先通过 axe-core 引擎扫描当前 HTML 文档,获取具体的无障碍违规项目和详细描述。然后将检测结果与原始源码结合,构建结构化的上下文提示词,为 AI 模型提供完整的问题背景和修复目标。
- 利用 VS Code 的语言模型 API 进行异步调用,确保 AI 能够基于具体问题生成针对性的修复方案。
- 智能代码提取与格式处理:针对 AI 模型输出的不确定性,设计多重正则表达式匹配策略,能够从不同格式的响应中准确提取 HTML 代码。通过代码清理算法去除多余的标记和格式,确保得到可直接使用的代码。
- 应用与状态同步:使用 WorkspaceEdit API 进行文档级别的完整替换操作,确保修复过程的原子性。修复完成后自动清除相关的诊断信息,并通过进度条和通知消息向用户反馈修复状态。
具体思路如下:
// AI修复无障碍问题的处理函数
export async function handleFixCommand(
textEditor: vscode.TextEditor,
axeScanner: AxeScanner,
context: vscode.ExtensionContext
) {
const editor = textEditor;
if (!editor) {
vscode.window.showErrorMessage("❌ 请先打开HTML文件");
return;
}
// 检查是否是 HTML 文件
if (editor.document.languageId !== "html") {
vscode.window.showWarningMessage("此功能仅支持 HTML 文件");
return;
}
// 显示进度提示
await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: "AI修复无障碍问题",
cancellable: false,
},
async (progress) => {
// 第一阶段:问题检测
progress.report({ increment: 0, message: "🔍 正在扫描问题..." });
const results = await axeScanner.scanDocument(editor.document);
if (!results?.violations.length) {
vscode.window.showInformationMessage("✅ 未发现问题!");
return;
}
progress.report({
increment: 30,
message: `发现 ${results.violations.length} 个问题`,
});
// 构造修复提示词 - 结合具体问题和源码
const fixPrompt = `修复以下HTML的无障碍问题:
当前代码:
${editor.document.getText()}
检测到的问题:
${results.violations
.map((v, i) => `${i + 1}. ${v.help} - ${v.description}`)
.join("\n")}
请返回修复后的完整HTML代码,只返回代码,不要解释。`;
// 第二阶段:AI 修复
progress.report({ increment: 50, message: "🔧 正在AI修复..." });
try {
// 获取可用的语言模型
const models = await vscode.lm.selectChatModels({
vendor: "copilot",
family: "gpt-4o",
});
if (models.length === 0) {
vscode.window.showErrorMessage(
"❌ 未找到可用的AI模型,请确保已登录GitHub Copilot"
);
return;
}
const model = models[0];
const messages = [
vscode.LanguageModelChatMessage.User(A11Y_SYSTEM_PROMPT),
vscode.LanguageModelChatMessage.User(fixPrompt),
];
// 调用 VSCode 的语言模型 API
const response = await model.sendRequest(messages, {});
let fixedCode = "";
for await (const fragment of response.text) {
fixedCode += fragment;
}
progress.report({ increment: 80, message: "🔧 处理修复结果..." });
// 代码提取算法 - 处理 AI 返回的格式化内容
const codeMatch =
fixedCode.match(/```html\n([\s\S]*?)\n```/) ||
fixedCode.match(/```\n([\s\S]*?)\n```/);
const cleanCode = codeMatch ? codeMatch[1].trim() : fixedCode.trim();
// 第三阶段:应用修复
progress.report({ increment: 90, message: "✅ 应用修复..." });
if (cleanCode && cleanCode !== editor.document.getText()) {
const edit = new vscode.WorkspaceEdit();
const fullRange = new vscode.Range(
0,
0,
editor.document.lineCount,
0
);
edit.replace(editor.document.uri, fullRange, cleanCode);
await vscode.workspace.applyEdit(edit);
// 清除所有诊断信息 - 表示问题已解决
const collection = vscode.languages.createDiagnosticCollection(
"accessibility-checker"
);
collection.set(editor.document.uri, []);
context.subscriptions.push(collection);
progress.report({ increment: 100, message: "✅ 修复完成!" });
vscode.window.showInformationMessage("✅ 修复完成!问题已自动解决。");
} else {
vscode.window.showWarningMessage("❌ 修复失败,请手动检查代码。");
}
} catch (error: any) {
vscode.window.showErrorMessage(`❌ AI修复失败: ${error.message}`);
console.error("AI修复失败:", error);
}
}
);
}
最终效果如下:
在需要进行无障碍检测的页面右键,选择AI修复无障碍问题

在右下角显示状态和进度

修复完成后,显示提示信息

总结与展望
在本文中,我们学习到了web界面设计中的无障碍功能,同时了解了最基本的无障碍设计原则。通过vscode提供的API,我们可以快速搭建一个扩展应用,辅助开发人员查找界面存在的问题。最后我们借助AI能力,可以自动修复无障碍缺陷。以下是一个本文使用的源码工程:https://gitee.com/GrapeCity/accessibility-checker
更多推荐




所有评论(0)