JavaScript中创建自定义元素需要遵循Web Components规范中的Custom Elements相关规则,通过浏览器提供的原生API即可完成自定义元素的注册和使用,不需要依赖第三方框架。

自定义元素的基础概念
自定义元素分为两类,一类是自主自定义元素,即完全独立的新元素,名称中必须包含短横线,比如<user-card>;另一类是自定义内置元素,继承自已有的原生HTML元素,比如继承自<button>的自定义按钮元素。
创建自定义元素的核心步骤是定义一个继承自HTMLElement的类,然后通过customElements.define方法将类注册为自定义元素。
自主自定义元素的创建步骤
1. 定义元素类
首先需要创建一个类,这个类必须继承自HTMLElement,我们可以在类的构造函数中初始化元素的内容、属性等。
// 定义自主自定义元素的类
class UserCard extends HTMLElement {
constructor() {
// 必须首先调用super(),继承HTMLElement的属性和方法
super();
// 初始化元素内容
this.innerHTML = `
<div class="user-card">
<h3>默认用户名</h3>
<p>默认用户简介</p>
</div>
`;
}
}
2. 注册自定义元素
定义好类之后,需要使用customElements.define方法将类注册到浏览器中,第一个参数是自定义元素的标签名,必须包含短横线,第二个参数是对应的类。
// 注册自定义元素,标签名为user-card
customElements.define('user-card', UserCard);
3. 在页面中使用自定义元素
注册完成之后,就可以像使用原生HTML元素一样在页面中使用这个自定义元素了,既可以直接写在HTML中,也可以通过JavaScript动态创建。
<!-- 直接在HTML中使用 -->
<user-card></user-card>
<script>
// 通过JavaScript动态创建
const card = document.createElement('user-card');
document.body.appendChild(card);
</script>
自定义元素的生命周期回调
自定义元素提供了多个生命周期回调函数,我们可以在对应的时机执行特定的逻辑:
- connectedCallback:当元素被插入到DOM树中时触发,适合做初始化操作、添加事件监听等。
- disconnectedCallback:当元素从DOM树中移除时触发,适合做清理操作,比如移除事件监听、清除定时器等。
- attributeChangedCallback:当元素的被监听的属性发生变化时触发,需要配合静态属性
observedAttributes使用。 - adoptedCallback:当元素被移动到新的文档时触发,比如使用
document.adoptNode方法时。
下面是一个使用生命周期回调的例子,实现当元素的name属性变化时更新显示内容:
class UserCard extends HTMLElement {
// 定义需要监听的属性列表
static get observedAttributes() {
return ['name', 'intro'];
}
constructor() {
super();
this.innerHTML = `
<div class="user-card">
<h3 id="name"></h3>
<p id="intro"></p>
</div>
`;
}
// 元素插入DOM时触发
connectedCallback() {
console.log('user-card元素被插入到DOM中');
// 初始化属性内容
this.updateContent();
}
// 监听的属性变化时触发
attributeChangedCallback(name, oldValue, newValue) {
console.log(`属性${name}从${oldValue}变为${newValue}`);
this.updateContent();
}
// 元素从DOM移除时触发
disconnectedCallback() {
console.log('user-card元素从DOM中移除');
}
// 更新元素内容的公共方法
updateContent() {
const nameEl = this.querySelector('#name');
const introEl = this.querySelector('#intro');
if (nameEl) {
nameEl.textContent = this.getAttribute('name') || '默认用户名';
}
if (introEl) {
introEl.textContent = this.getAttribute('intro') || '默认用户简介';
}
}
}
// 注册元素
customElements.define('user-card', UserCard);
使用的时候可以通过设置属性来更新内容:
<user-card name="张三" intro="前端开发工程师"></user-card>
<script>
const card = document.querySelector('user-card');
// 修改属性,会触发attributeChangedCallback
setTimeout(() => {
card.setAttribute('name', '李四');
card.setAttribute('intro', '后端开发工程师');
}, 2000);
</script>
为自定义元素添加样式
自定义元素内部的样式可以通过两种方式添加,一种是直接在外部CSS中编写对应标签的样式,另一种是使用shadow DOM封装内部样式,避免外部样式污染。
方式一:外部CSS样式
直接在页面的CSS中写自定义元素的样式即可,和原生元素的样式写法一致。
/* 外部样式作用于user-card元素 */
user-card {
display: block;
width: 300px;
border: 1px solid #ccc;
padding: 16px;
border-radius: 8px;
}
user-card h3 {
color: #333;
margin: 0 0 8px 0;
}
user-card p {
color: #666;
margin: 0;
}
方式二:使用Shadow DOM封装样式
在构造函数中创建Shadow DOM,将元素内容放在Shadow DOM内部,内部的样式只作用于Shadow DOM内部,不会影响到外部。
class UserCard extends HTMLElement {
constructor() {
super();
// 创建开放模式的Shadow DOM
const shadow = this.attachShadow({ mode: 'open' });
// Shadow DOM内部的内容
shadow.innerHTML = `
<style>
/* 样式只作用于Shadow DOM内部 */
.container {
width: 300px;
border: 1px solid #ccc;
padding: 16px;
border-radius: 8px;
}
h3 {
color: #333;
margin: 0 0 8px 0;
}
p {
color: #666;
margin: 0;
}
</style>
<div class="container">
<h3>默认用户名</h3>
<p>默认用户简介</p>
</div>
`;
}
}
customElements.define('user-card', UserCard);
自定义内置元素的创建
如果需要继承自已有的原生元素,比如创建一个带计数功能的<button>,可以创建自定义内置元素,定义类的时候继承对应的原生元素类,注册的时候传入第三个参数指定继承的原生元素。
// 继承HTMLButtonElement
class CountButton extends HTMLButtonElement {
constructor() {
super();
this.count = 0;
this.textContent = `点击次数:${this.count}`;
// 添加点击事件
this.addEventListener('click', () => {
this.count++;
this.textContent = `点击次数:${this.count}`;
});
}
}
// 注册自定义内置元素,第三个参数指定继承的原生元素
customElements.define('count-button', CountButton, { extends: 'button' });
使用自定义内置元素的时候需要指定is属性:
<button is="count-button"></button>
注意事项
- 自定义元素的标签名必须包含至少一个短横线,否则注册的时候会报错。
- 自定义元素的类必须继承自HTMLElement或者对应的原生元素类,构造函数中必须首先调用
super()。 customElements.define必须在自定义元素被创建之前调用,否则浏览器会将其当作未知元素处理。- 如果需要监听属性变化,必须定义静态属性
observedAttributes,返回需要监听的属性名数组,否则attributeChangedCallback不会触发。 - 自定义元素目前主流现代浏览器都已经支持,如果需要兼容旧版本浏览器,需要引入对应的polyfill。
JavaScript自定义元素Custom_ElementsWeb_Components修改时间:2026-07-21 02:39:37