customelements.define 必须等第三方库加载完成后再调用,否则会报“name already used”或渲染失败;需通过 onload 回调、轮询全局变量或动态 import 确保库就绪;attributechangedcallback 中需显式调用库的更新方法而非仅改属性;shadow dom 会导致 chart.js/leaflet 失效,应避免或显式传入渲染目标;disconnectedcallback 中必须手动调用 destroy/remove 并清理定时器和观察者。

customElements.define 必须等第三方库加载完再调用
直接在 <script></script> 里写 customElements.define('my-chart', ChartComponent) 却发现报错 Failed to execute 'define' on 'CustomElementRegistry': the name "my-chart" has already been used,或者组件根本没渲染——大概率是 Chart.js、Leaflet 这类库还没加载完,你就注册了自定义元素。
正确做法是确认全局变量就位后再注册。常见方式有:
- 监听
<script src="chart.js"></script>的onload回调,在回调里调用customElements.define() - 用
document.readyState === 'complete'+setTimeout轮询检查window.Chart是否存在(适合简单场景) - 若用 ES 模块动态导入,改用
import('chart.js').then(() => customElements.define())
attributeChangedCallback 不能替代 update() 方法
监听 data-config 或 data-series 属性变更后,只在 attributeChangedCallback 里解析 JSON、重写 innerHTML 或清空容器,界面不会真正更新——因为第三方实例(如 this._chart)没被通知。
必须显式调用库的更新接口:
-
Chart.js:首次用new Chart(ctx, config),后续改this._chart.data.datasets = [...]后调this._chart.update() -
Leaflet:先this._map.remove()清理旧图层,再重建并调this._map.setView() - 避免每次解析
data-config字符串,建议存为对象属性:this._config = JSON.parse(val)
Shadow DOM 会让 Chart.js / Leaflet 失效
在 this.attachShadow({ mode: 'open' }) 里插入 <canvas></canvas> 或 <div id="map"></div>,Chart.js 初始化失败、Leaflet 报 InvalidSizeError——这不是 bug,是 Shadow DOM 切断了样式继承和 DOM 查询链,而这些库依赖父级容器的 CSS 尺寸、定位上下文,甚至明确禁止在 Shadow 中渲染(如 Mapbox GL)。
绕过方案只有两个现实选择:
- 放弃 Shadow DOM,用 light DOM + 命名空间类(如
.my-chart-wrapper),靠 CSS 作用域隔离 - 保留 Shadow DOM,但把渲染目标(
ctx或div)显式传入第三方初始化逻辑,不依赖内部querySelector
disconnectedCallback 里必须手动销毁实例
组件从 DOM 移除时,disconnectedCallback 不会自动清理 Chart 实例、Map 对象、定时器或 MutationObserver —— 导致内存泄漏和重复事件绑定。
销毁动作必须显式写:
-
Chart.js:调this._chart.destroy() -
Leaflet:调this._map.remove(),再置空引用this._map = null - 清除所有
setInterval/setTimeoutID,并调observer.disconnect()
最容易被忽略的是:第三方库的销毁方法名不统一(destroy、remove、off),得查对应文档;而且有些库销毁后再次 init 会出错,必须确保实例彻底释放。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











