推荐用 <template> 标签定义组件骨架,配合 JS 克隆插入,确保静态托管环境兼容、HTML 可独立验证;类名需带统一前缀防样式泄漏;语义化标签划定逻辑边界;暴露语义化属性与事件,避免内部状态泄露。

用 做组件骨架,别依赖服务端 include
静态托管环境(如 GitHub Pages、Netlify)不解析 PHP 的 <?php include ?> 或 EJS 模板语法,直接写死片段会导致 HTML 被当作文本渲染,结构失效。必须用浏览器原生支持的方案。
推荐做法是把组件结构写在 <template id="c-button"> 里,JS 中用 document.getElementById('c-button').content.cloneNode(true) 插入。这样既保持 HTML 可独立复制验证,又避免运行时请求开销。
- 每个
<template>必须有唯一id或data-role属性,防止 JS 初始化时错绑事件 - 不要把
<template>放在<body>外或注释里——部分旧版 Safari 会忽略 - 若需动态加载外部 HTML(如
fetch('./components/c-modal.html')),要处理 CORS 和缓存头,否则本地双击打开会失败
结构自闭合 + 命名空间类名,防样式泄漏
没 Shadow DOM 时,CSS 泄漏是默认行为。<div class="card"> 这种泛化名一上线就和项目其他样式打架,不是“可能冲突”,是“必然冲突”。
正确写法是:组件 HTML 必须能单独复制进任意页面正常渲染,且所有类名带统一前缀,比如 c-button、c-card__header、c-modal--small。
立即学习“前端免费学习笔记(深入)”;
- 禁用
<section>包裹组件——它语义是“主题性分组”,不是“视觉容器”,会干扰<h1>–<h6>嵌套逻辑 - 按钮必须用
<button>标签,不能用<div role="button">—— 否则表单提交、键盘焦点、无障碍支持全失效 - 所有组件内距、边框、阴影必须基于 CSS 自定义属性(如
var(--c-space-md)),禁用!important和px固定值
语义标签划定逻辑边界,别用 div 堆结构
<div class="wrapper"><div class="container"><div class="row"> 这类嵌套不是“结构”,是样式草稿本。它让后续任何新增模块都得猜这个 div 是干啥的,也锁死了 flex/grid 的布局能力。
用 <header>、<main>、<nav>、<footer> 划定逻辑边界:<main> 只能出现一次,且必须包裹页面核心内容;<section> 表示可独立分发的内容单元(如博客条目),不是视觉容器。
- 避免
<section>套<section>超过两层——第三层开始,应考虑抽成独立组件或改用<nav> - 三栏布局优先用 grid:
grid-template-areas: "header header header" "nav main aside",加新栏只需改一行 CSS,不用动 HTML - 保持语义顺序(
<main>在前),视觉顺序用grid-column或flex-direction: row-reverse控制,别为了 float 把侧边栏写在<main>前面
暴露语义化属性与事件,别把内部状态全扔出去
开发者看到 <c-date-picker>,第一反应应该是“传个 value 就能用”,而不是翻文档查 setInitialDate()。暴露 isFocused、hasError 这类内部状态,等于强迫使用者手动同步,反而更难维护。
只暴露语义化属性(value、min、disabled),其余状态通过事件(change、focus)或方法(focus()、reset())控制。布尔属性如 disabled 必须用 hasAttribute('disabled') 判断,不能依赖 this.disabled === true(未设置时值为 undefined)。
-
attributeChangedCallback里别直接更新 DOM——浏览器可能批量触发,频繁操作会卡顿;用Promise.resolve().then(() => { /* 更新 */ })延迟合并执行 - 字符串类属性(如
format)先做浅比较:if (oldValue === newValue) return,避免无意义重渲染 - 对外方法统一返回
Promise,哪怕当前是同步实现——“以后加校验逻辑不用改调用方”
真正卡住可扩展性的,往往不是技术选型,而是结构和样式的职责错位:HTML 写成样式草稿本,CSS 写成结构修补胶带。一旦某天要加暗色模式或响应式断点,就会发现所有地方都在互相牵制。



















