components/目录该建,仅当存在真实复用行为——如页头被三个以上页面复制粘贴,或已引入vite-plugin-html、gulp-file-include等构建注入机制;否则仅为冗余文件夹。

components/目录该不该建,取决于你是否真在复用
组件化不是结构上的“有目录就高级”,而是行为上的“改一处,多处生效”。如果你只是把页头、卡片、表单各写一遍,再分别丢进 components/header.html、components/card.html,但没配套的加载机制或构建流程,那这个目录只是文件夹套娃,反而增加路径维护成本。
真正该建 components/ 的信号只有两个:header.html 被至少三个页面直接复制粘贴过;或者你开始用 vite-plugin-html、gulp-file-include 或服务端模板(如 PHP include)做内容注入。否则,一个只有 <nav><ul><li>...</li></ul></nav> 的 nav.html,不如直接写在 index.html 里——抽象成本远高于收益。
- 每个组件子目录名必须与内部主文件名一致:如
components/header/下必须有header.html、header.css、header.js,命名不统一会导致构建工具或脚本引用断裂 - 组件内资源引用必须用相对路径,且基于组件自身位置计算:比如
components/header/header.css里写background: url(../images/logo.svg)是错的,应写url(../../images/logo.svg)或更好——改用根路径url(/images/logo.svg) - 别在组件 HTML 里硬编码业务数据:例如
header.html不该写死<h1>My Company</h1>,而应留空或用data-title属性,由宿主页面传入
pages/ 页面如何安全引用 components/ 内容
纯静态 HTML 项目中,浏览器无法原生解析 <include src="components/header.html"></include> 这类语法。双击打开或本地 HTTP 服务未配置 SSI 时,这类写法直接白屏或触发 CORS 错误。
可行路径只有两条:构建时拼接,或服务端包含。前者依赖工具链,后者依赖服务器能力。没有中间态。
- 用
gulp-file-include时,pages/about.html中写<!-- include "components/header.html" -->,路径是相对于pages/目录算的,不是根目录——所以实际要写成<!-- include "../components/header.html" --> - 用 Vite +
vite-plugin-html时,模板语法如,路径基于src/,且必须用 Nunjucks/EJS 等支持 include 的模板引擎,纯.html文件不生效 - 若走服务端包含(如 Apache 的 SSI 或 Nginx 的
ssi模块),HTML 必须以.shtml后缀保存,且服务器需开启对应模块,本地双击打开仍会失败
assets/ 和 public/ 到底谁放 favicon.ico
favicon.ico 必须放 public/,不能放 assets/ 或 src/。这是构建工具(Vite/Webpack)的硬性规则:只有 public/ 下的文件才会被原样复制到 dist/ 根目录,其他路径下的文件默认不参与输出。
如果把它塞进 assets/images/favicon.ico,构建后 dist/favicon.ico 就不存在,浏览器请求 /favicon.ico 时返回 404,地址栏小图标消失——而控制台通常不报错,只默默忽略。
-
public/只放不参与编译的静态资源:favicon.ico、robots.txt、manifest.json、crossdomain.xml -
assets/是源码级资源目录,用于组织可被构建流程处理的内容:比如assets/images/logo.svg可能被 Webpack 的url-loader转成 base64,或被 Vite 的import解析为 URL 字符串 - 所有 HTML 中对
public/资源的引用必须用根路径:<link rel="icon" href="/favicon.ico">,而不是href="favicon.ico"或href="../favicon.ico"
组件样式怎么避免污染全局 CSS
HTML 组件没有天然作用域,components/header/header.css 里写的 h1 { color: blue; } 会全局生效,可能意外覆盖 pages/blog.html 里的文章标题样式。
不用框架时,唯一可靠的方式是手动加类前缀 + 显式作用域限定:
- 外层容器必须带唯一类名:
<header class="cmp-header">...</header>,所有样式规则都以此为父选择器:.cmp-header h1 { color: blue; } - 子元素用 BEM 命名:
.cmp-header__logo、.cmp-header__nav、.cmp-header__item,杜绝div div h1这类宽泛选择器 - 避免用
!important——它会让后续覆盖变得不可预测,真需要强制覆盖时,靠更具体的选择器(如.cmp-header.cmp-header--dark h1)来实现 - 如果用了 CSS 预处理器(Sass/Less),可在组件 CSS 文件顶部用
@import引入变量,但禁止跨组件直接@import '../base/reset.css',否则移动组件目录时路径全断
组件化最难的部分从来不是目录怎么摆,而是人愿不愿意遵守边界约定。一个没加前缀的 .card 类,比十个嵌套的 components/ 子目录更容易让项目失控。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











