<p>真正能落地的只有构建时静态检查 + 运行时属性拦截双轨机制:构建时用 ESLint 插件校验 HTML 质量,运行时在 attributeChangedCallback 中拦截非法 class/id/data-* 属性并告警。</p>

直接在基类里加 HTML 质量校验逻辑,既不能拦截已渲染的 DOM,也拦不住模板字符串拼接——真正能落地的只有构建时静态检查 + 运行时属性拦截双轨机制。
为什么基类 constructor 里做 innerHTML 拦截根本无效
很多人试图在自定义元素基类的 constructor 中重写 innerHTML setter,或监听 connectedCallback 后遍历子节点做 class/id 校验。这看似主动,实则失效:
- DOM 已完成解析和样式计算,class="btn" 冲突、id 重复、data-* 命名不规范等问题早已污染全局作用域
-
innerHTML = htmlString是同步操作,拦截点必须在赋值前(比如模板编译阶段),而非 DOM 挂载后 - 第三方库(如 Ant Design)注入的
<style>不经过你的基类,adoptedStyleSheets也管不了它
真正起效的两个拦截层:构建时 + 运行时
HTML 质量约束必须分层嵌入,缺一不可:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
-
构建时层:用 ESLint 插件
eslint-plugin-html+ 自定义规则校验class是否首位、id是否唯一、data-是否小写短横线、属性值是否双引号包裹。CI 流程中失败即阻断发布 -
运行时层:在基类
attributeChangedCallback中拦截class、id、data-*属性变更,对非法值抛警告(非报错),并记录到window.__htmlLintLog供调试面板查看 - 禁止在基类中尝试修复值(如自动补引号、重排属性顺序),这会掩盖真实问题,且与 SSR 渲染结果不一致
data-* 属性校验最容易被绕过,但恰恰最危险
团队常以为 data-testid 或 data-track 只是“标记”,不影响功能。实际上:
立即学习“前端免费学习笔记(深入)”;
- 未校验的
data-user-id="123"会被el.dataset.userId正确读取,但data-userID="123"就变成undefined—— 因为 dataset 自动驼峰转换只认短横线分隔 -
data-config='{"theme":"dark"}'是合法的,但data-config={theme: "dark"}(无引号+对象字面量)会触发 HTML 解析器截断,导致后续属性丢失 - 构建时规则必须覆盖所有
data-*,而不仅是白名单里的几个;运行时拦截应拒绝以数字开头的 key(如data-1st-item),旧版 Safari 会静默忽略
复杂点不在代码怎么写,而在“谁负责触发校验”——构建时靠 CI 卡口,运行时靠基类暴露可配置开关(如 enableHtmlLint: true),但默认关闭。开着它跑生产环境?别试。它只该出现在 devtools 面板里,作为调试辅助,不是防御墙。


















