html 应仅保留语义化结构和 js/css 钩子(如 class="js-modal-trigger"、data-id="123"),事件绑定须用 addeventlistener,样式修改须通过 classlist 切换预定义类,禁用内联 style 和 onclick;css 类名需语义化(如 bem)、避免视觉/布局细节;js 禁止拼接 html 字符串,优先用模板片段或 createelement + textcontent;三者物理分离但协作点需明确、文档化、可检测。

HTML 不该写 onclick 或内联 style
直接在 HTML 标签里写 onclick="doSomething()" 或 style="color: red;",等于把行为和样式逻辑硬编码进结构层。一旦要改交互方式或换主题色,就得满 HTML 文件里搜替换,还容易漏掉。
常见错误现象:button onclick="alert('提交成功')" 看似简单,但后续加表单校验、异步提交、埋点统计时,逻辑全得塞进这个字符串里,根本没法单元测试。
- 所有事件绑定必须用 JS 通过
addEventListener动态挂载,且优先用委托(如监听document或父容器) - 禁止用
element.style.xxx = ...改样式;统一操作className或classList切换预定义的 CSS 类 - HTML 中只保留语义化结构和必要钩子,比如
class="js-modal-trigger"或data-id="123",不带任何样式或行为含义
CSS 类名不该暴露实现细节
用 .red-button 或 .left-nav 这类名字,等于把视觉表现和布局强绑在 HTML 结构上。换深色模式时得批量重命名,页面重构时一动布局就废掉一堆类。
使用场景:一个商品卡片组件要在首页、搜索页、详情页复用,如果它依赖 .grid-3-col 这种布局类,那在详情页单列展示时就得额外写覆盖规则,越积越多。
- 采用 BEM 或类似语义命名,如
.product-card、.product-card__price、.product-card--on-sale - 工具类单独隔离,用前缀区分,比如
u-text-center(u 表示 utility),且只用于纯排版/间距/颜色等原子级效果 - JS 钩子类明确标记,如
js-dropdown-toggle,CSS 里不写任何样式,纯粹作 DOM 定位用
JS 不该拼接 HTML 字符串
element.innerHTML = '<div class="item">' + data.title + '</div>' 这种写法,等于把模板逻辑塞进 JS,破坏了 HTML 的语义完整性,也绕过了 SSR 和静态分析工具的检查。
性能影响:每次拼字符串都触发重排重绘;安全风险:没做转义就插入用户数据,直接 XSS;维护成本:UI 变动时,JS 和 HTML 两头都要改。
- 优先用隐藏的模板片段,如
<template id="item-template"><div class="item">{{title}}</div></template>,JS 中克隆后填充 - 服务端渲染或构建时生成静态 HTML 片段,前端只负责 hydrate 和交互接管
- 若必须动态生成,用
document.createElement+textContent组合,避免直接拼接标签字符串
三者物理分离,但协作点要清晰可控
解耦不是消灭所有关联,而是让关联可预测、可定位。比如一个按钮点击后显示弹窗,这个“点击 → 显示”链路,必须只通过一个明确的 class 名或 data 属性触发,不能靠 DOM 层级路径(如 parent.nextElementSibling.querySelector('.modal'))——层级一变就断。
容易被忽略的地方:很多人以为把 JS 拆成单独文件、CSS 提成外链就叫解耦了,但若 JS 里还大量用 document.querySelector('header nav > ul > li:first-child a'),那 HTML 结构一调整,JS 就崩,实际耦合一点没少。
- 所有跨层通信点(HTML ↔ JS ↔ CSS)必须文档化,比如约定
data-behavior="tabs"对应某段 JS 初始化逻辑 - 构建流程中加入检查项,如禁止 JS 文件里出现
innerHTML =、禁止 CSS 里用:not(.js-enabled) *这类反向依赖 - 团队协作时,后端改 HTML 模板前,先看有没有
js-类或data-属性被 JS 依赖,而不是靠口头同步
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











