提升html重用性需分层施策:构建期用posthtml-include内联片段,运行时用custom elements+shadow dom封装自治组件,语义结构须透传;混用三者反增维护成本。

纯 HTML 本身不提供组件重用能力,所谓“提升重用率”本质是选对介入时机和封装层级——构建期内联、运行时 Custom Elements、语义结构透传,三者不可混用,否则反而增加维护成本。
用 posthtml-include 做构建期复用,别在浏览器里 fetch
动态加载 header.html 再 innerHTML 插入,看着省事,实际导致样式丢失、脚本不执行、SEO 抓不到、无障碍树断裂。这不是“复用”,是把构建问题甩给运行时。
-
posthtml-include必须在构建阶段工作:Webpack 的html-loader或 Vite 的vite-plugin-html都能实现,最终输出的是标准 HTML 字符串,无任何 JS 依赖 - 语法必须是
<include src="partials/header.html"></include>,不是注释、不是自定义标签、不支持嵌套路径别名 - 所有
src路径以入口 HTML 文件为基准,比如pages/about.html引用partials/nav.html,路径就得写成../partials/nav.html - partial 文件里禁止写
<script></script>标签——交互逻辑统一收口到主页面 JS 中初始化
用 customElements.define() 封装带行为的组件,别只塞 div
注册一个 <product-card></product-card> 却在 Shadow DOM 里全用 <div class="title">,等于放弃语义。屏幕阅读器读不出它是“产品”,搜索引擎无法识别它是独立内容单元,后期加 ARIA 是补救,不是设计。
<ul><li>外层容器优先用语义标签:卡片用 <code><article></article>,导航用 <nav></nav>,图文组合用 <figure></figure>,不要用 <div role="article"> 降级兜底
<li>
<code><slot></slot> 必须命名且语义化:<slot name="title"></slot> 比 <slot></slot> 更可控;使用者传 <h3 slot="title">新品上市</h3>,组件才真正可组合
mode="closed" 会屏蔽全局样式,若需继承基础排版(如字体、链接颜色),显式设为 mode="open"
this.shadowRoot 上:this.shadowRoot.addEventListener('click', ...),不是 document.addEventListener
用 <template></template> 做轻量级模板,但别指望它自动响应数据
<template></template> 是静态内容容器,不是 Vue 的 <template></template>。它不解析 JS、不执行 script、不加载图片,克隆后所有动态填充都得手动做。
- 适合场景:用户列表卡片、模态框骨架、表单字段组——结构固定、数据由 JS 控制
- 不能直接在 template 内写
<img src="%7B%7Bavatar%7D%7D">,必须用 JS 手动设置card.querySelector('img').src = user.avatar - 如果需要条件渲染或循环,
<template></template>不够用,该上 Web Components 或框架 - IE11 支持
<template></template>,但不支持content.cloneNode(true)的深度克隆,需 polyfill 或降级处理
最容易被忽略的点是语义与封装的耦合:一个 <nav-bar></nav-bar> 组件若内部用 <div class="nav-list">,那它就只是个视觉盒子;若内部是 <code><nav><ul><li><a></a></li></ul></nav>,它才是可被爬虫索引、被键盘导航跳转、被屏幕阅读器识别的真正导航单元。重用率不取决于代码是否“写一遍用十遍”,而取决于它在语义、样式、行为三个维度是否真正自治。











