直接 innerhtml = template.innerhtml 会销毁并重建 dom 节点,导致表单选中态丢失、输入内容清空、事件绑定失效;应使用 document.importnode(tmpl.content, true) 克隆以保留状态。

纯 HTML + CSS 组件库若想真正可维护,<template></template> 不能当“组件语法糖”用——它只是静态容器,所有逻辑、状态、样式隔离都得靠你手动补全。没这层认知,写出来的所谓“组件”三个月后就没人敢动。
为什么直接 innerHTML = template.innerHTML 会毁掉表单状态
常见错误是把 <template></template> 当成字符串模板,用 innerHTML 直接塞进页面。这会导致:<input checked> 失去选中态、<select></select> 回到默认项、<textarea></textarea> 内容清空——因为 innerHTML 会销毁并重建 DOM 节点,所有用户输入和 JS 绑定全部丢失。
- 必须用
document.importNode(tmpl.content, true)克隆,它保留表单控件的当前值和焦点状态 - 禁止在模板里写
id="submit-btn"—— 多次渲染必然重复 ID,后续document.getElementById()只取第一个 - 如果模板含
<script></script>标签,importNode不会执行它;得手动遍历 script 节点,创建新元素并 append 到 document
data-bind 属性比 class 名更适合做内容锚点
类名是给 CSS 用的,不是给 JS 填数据用的。用 class="card-title" 做绑定目标,一旦设计师改名成 card-header-text,JS 就静默失效;而 data-bind="title" 是语义契约,跟样式无关。
- 绑定字段统一用小写短横线格式:
data-bind="primary-action",避免大小写混用或空格 - 文本内容用
textContent填充,HTML 内容用innerHTML(但需提前做 XSS 过滤) - 不要在模板里写
{{title}}这类插值——原生 HTML 不解析,JS 也得额外写正则替换,易出错且难调试
组件根节点必须带 data-module,且禁用 class 做模块标识
靠 class="c-card" 查组件,等于把样式逻辑和模块职责绑死。CSS 重构时改个类名,JS 就断;多人协作时加个 c-card--new,没人知道旧 JS 是否兼容。
- 每个组件外层容器加
data-module="card",JS 用document.querySelectorAll('[data-module="card"]')稳定定位 - 配置走
data-config='{"size": "large", "variant": "outline"}',而不是一堆data-size="large" data-variant="outline" - 禁止在 CSS 中写
[data-module="card"] { ... }—— 这会让样式依赖模块属性,违背“结构归结构、样式归样式”原则
命名空间前缀 + CSS 自定义属性是防泄漏的底线
没有 Shadow DOM 时,CSS 泄漏不是“可能”,而是“默认发生”。一个 .button 类名,很可能被项目其他样式覆盖或反向影响。
- 所有类名强制前缀:
c-button、c-card__body、c-modal--dark,禁用button、modal这类泛化名 - 间距、颜色、圆角全部抽成 CSS 变量:
--c-space-md、--c-color-primary,禁用margin: 8px或color: #0066cc - 禁止
!important—— 它锁死下游主题切换能力,深色模式或品牌定制直接失效
最难的部分不是写模板,而是坚持让每个组件能单独复制进任意页面就正常工作:不依赖全局样式、不污染外部 DOM、不假设父容器存在。这点做不到,所谓“组件库”只是带前缀的代码片段集合而已。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











