Skip to content

自定义元素

Web 组件之一,如果想得到良好兼容,请使用 polymer

规范

  1. 自定义元素名必须至少包含一个不在名称开头和末尾的连字符
  2. 元素标签不能自关闭

创建自定义元素

  1. 自定义元素的未来源自类
  2. 调用 customElements.define() 创建自定义元素
js
class FooElement extends HTMLElement {
    constructor() {
        super();
        console.log('x-foo')
    }
}
customElements.define('x-foo', FooElement)

document.body.innerHTML = '<x-foo></x-foo>' // x-foo

可以使用 customElements.get() 方法返回相应自定义元素的类

添加子元素

  • 不能再构造函数中添加子 DOM,会报错
  • 但可以添影子 DOM
js
class FooElement extends HTMLElement {
    constructor() {
        super();
        
        this.attachShadow({ mode: 'open' })
        	.innerHTML = '<p>hello world</p>'
    }
}
customElements.define('x-foo', FooElement)
document.body.innerHTML = '<x-foo></x-foo>'

生命周期

  • 可以定义其生命周期
生命周期调用时间
constructor()创建元素实例或将已有 DOM 元素升级为自定义元素时
connectedCallback()在每次将这个自定义元素实例添加到 DOM 中时
disconnectedCallback()在每次将这个自定义元素实例从 DOM 中移除时
attributeChangedCallback()在每次可观察属性的值发生变化时,在元素实例初始化时也算一次
adoptedCallback()在通过 document.adoptNode() 将这个自定义元素实例移动到新文档对象时
js
class FooElement extends HTMLElement {
    constructor() {
        super()
        console.log('ctor')
    }
    
    connectedCallback() {
        console.log('connected')
    }
    
    disconnectedCallback() {
        console.log('disconnected')
    }
}
customElements.define('x-foo', FooElement)

const fooElement = document.createElement('x-foo') // ctor
document.body.appendChild(fooElement)              // connected
document.body.removeChild(fooElement)              // disconnected

自定义属性

  • 通过设置控制器获取和设置属性
  • 还需要设置监听器配合attributeChangedCallback()生命周期
js
class FooElement extends HTMLElement {
    static get observedAttributes() {
        // 返回应该触发 attributeChangedCallback 生命周期的属性
        return ['name']
    }
    
    get name() {
        return this.getAttribute('name')
    }
    
    set name(value) {
        this.setAttribute('name', value)
    }
    
    attributeChangedCallback(key, oldValue, newValue) {
        if (oldValue !== newValue) {
            this[key] = newValue
        }
    }
}
customElements.define('x-foo', FooElement)

升级自定义属性

  • 可以使用 customElements.whenDefined() 返回一个期约,当相应自定义元素有定义之后解决
  • 可以使用 customElements.upgrade() 强制升级