最稳妥的动态创建方式是document.createElement(),它返回真实DOM节点,天然防XSS,支持安全绑定事件和属性;自定义元素需先define再创建,attribute与property不可混用,innerHTML插入不会触发升级。

document.createElement() 是最稳妥的创建方式
直接拼 HTML 字符串(比如用 innerHTML)看似快,但容易 XSS、属性转义错乱、事件绑定失效。真正安全可控的动态创建,首选 document.createElement()。
- 它返回的是真实 DOM 节点,不是字符串,天然规避 HTML 注入风险
- 所有属性、事件、样式都通过 JS 对象操作,类型和值由 JS 运行时校验,不会出现
undefined被插进标签里这种低级错误 - 适合需要后续交互的元素,比如你刚创建的按钮,马上就能绑
addEventListener('click', ...) - 注意:
document.createElement('custom-element')不会自动升级为自定义组件,必须先用customElements.define()注册过才行
给动态元素加自定义属性要分清 attribute 和 property
比如你想给一个 <user-card> 加上 data-user-id="123" 或 userId="123",写法和效果完全不同。
- 用
element.setAttribute('data-user-id', '123')—— 写进 HTML 特性(attribute),可在 DevTools 里看到,也支持 CSS 选择器[data-user-id] - 用
element.userId = 123—— 写进 DOM 属性(property),只在 JS 中可读,不反映在 HTML 源码里,也不触发 attributeChangedCallback - 自定义元素内部想响应变化,必须靠
static get observedAttributes()+attributeChangedCallback,而这只监听setAttribute触发的 attribute 变更 -
dataset是便捷入口:element.dataset.userId = '123'等价于setAttribute('data-user-id', '123')
动态插入后,自定义元素可能没升级?检查 define 时机
常见现象:元素已 append 到页面,但 console.log(element.constructor.name) 还是 HTMLUnknownElement,说明没升级成功。
使用 Puppeteer + Chrome 将 HTML 渲染为中文 PDF,自动处理图表等待、Tab 展开、动画、测高、白边消除、防分页,适用于看板、报表、网页和交互图表转 PDF。
- 必须在调用
document.createElement('my-button')之前,完成customElements.define('my-button', MyButton) - 如果脚本异步加载或延迟执行,很可能
define还没跑完,DOM 就已经插入了——这时元素会“挂起”,直到 define 完成才升级(现代浏览器支持,但别依赖) - 保险做法:先
define,再批量创建;或者用customElements.whenDefined('my-button').then(...)确保升级后再操作 - 不要在
connectedCallback里重复define,会报错 “Custom element already registered”
innerHTML 插入含自定义标签的字符串,不会触发升级
这是最容易踩的坑:你写了 container.innerHTML = '<my-input value="test"></my-input>',结果发现它只是个普通标签,没行为、没样式、没生命周期。
立即学习“前端免费学习笔记(深入)”;
-
innerHTML解析出来的节点,属于“被动插入”,浏览器不会主动调用customElements.define去匹配和升级 - 即使该标签名已注册,也不会自动补上构造函数和原型链
- 唯一可靠路径:先用
document.createElement('my-input')创建,再设置element.value = 'test',最后append - 若真要批量渲染,建议用模板字符串生成纯数据结构,再用循环 +
createElement构建节点,而不是拼 HTML 字符串
define 顺序、混用 attribute/property、依赖 innerHTML 升级,这三处出错频率最高。


















