初探 web components

經過使用 Custom Elements 建立內聯的 CSS 和 JavaScript 的自定義元素。須要說明的是它不是 React, Vue 或者 Angular 的框架的替代方案,它是一個全新的概念。javascript

建立徹底的自定義元素

CustomElementRegistry 對象

在 window 全局對象下暴露了 customElements 屬性,能夠經過此屬性訪問到 CustomElementRegistry 對象。 CustomElementRegistry 對象下的幾種方法用於註冊 Custom Elements和查詢 Custom Elements:css

  • define()用於定義新的 Custom Element
  • get() 用於獲取 Custom Element 的 constructor,若是不存在,返回 undefined
  • upgrade() 用於升級 Custom Element
  • whenDefined() 用於獲取 Custom Element 的 constructor,相似 get(),不一樣之處是返回值是 promise,有可用值是返回 resolves 狀態

如何建立一個 Custom Element

在調用 window.customElements.define() 方法前,首先要定義一個新的HTML元素html

class CustomTitle extends HTMLElement {
    // ToDo...
}
複製代碼

在 CustomTitle 類的構造器中使用 Shadow DOM 關聯自定義 CSS,JavaScript 和 HTML到新的元素,這樣就能夠在這個新元素中封裝各類功能,首先初始化構造器java

class CustomTitle extends HTMLElement {
    constructor() {
        super()
        //...
    }
}
複製代碼

而後調用 attachShadow(),傳入參數 { mode: 'open' } ,這個屬性設置了 shadow DOM的封裝模式,若是設置值爲 open,能夠訪問元素的 shadowRoot 屬性,若是值爲 close,則不能夠。git

class CustomTitle extends HTMLElement {
    constructor() {
        super()
        this.attachShadow({ mode: 'open' })
        //...
    }
}
複製代碼

接下來設置元素的HTMLes6

class CustomTitle extends HTMLElement {
    constructor() {
        super()
        this.attachShadow({ mode: 'open' })
        this.shadowRoot.innerHTML = ` <h1>Hello WC!</h1> `
    }
}
複製代碼

這裏的 innerHTML 能夠寫入多個 html taggithub

定義了內置元素後,便可使用 window.customElementsweb

window.customElements.define('custom-title', CustomTitle)
複製代碼

以上便可在頁面中使用 數組

加入CSS

class CustomTitle extends HTMLElement {
  constructor() {
    super()
    this.attachShadow({ mode: 'open' })
    this.shadowRoot.innerHTML = ` <style> h1 { font-size: 40px; color: #000; } </style> <h1>Hello WC!</h1> `
  }
}
複製代碼

簡寫語法

window.customElements.define('custom-title', class extends HTMLElement {
  constructor() {
    ...
  }
})
複製代碼

加入 JavaScript

在加入JavaScript處理方式上與 CSS 上略有區別,不能再模板字符串中直接寫入,須要加入 addEventListener處理promise

class CustomTitle extends HTMLElement {
    constructor() {
        super()
        this.attachShadow({ mode: 'open' })
        this.shadowRoot.innerHTML = ` <style> h1 { font-size: 40px; color: #000; } </style> <h1>Hello WC!</h1> `
    this.addEventListener('click', e => {
    	console.log('clicked')
    })
  }
}
複製代碼

demo 連接

使用 template

可使用 template,經過id指定到

<template id="custom-title-template">
  <style> h1 { font-size: 40px; color: #000; } </style>
  <h1>Hello WC!</h1>
</template>

<custom-title></custom-title>
複製代碼

而後在 Custom Element 構造器中引用到 shadow DOM 上

class CustomTitle extends HTMLElement {
    constructor() {
        super()
        this.attachShadow({ mode: 'open' })
        const tmpl = ducument.querySelector('#custom-title-template')
        this.shadowRoot.appendChild(tmpl.content.cloneNode(true))
  }
}

window.customElements.define('custom-title', CustomTitle)
複製代碼

demo 連接

生命週期

除 constructor 外,還能夠定義生命週期函數,用於在特定時期執行特定的方法

  • connectedCallback 當元素插入到DOM中時執行
  • disconnectedCallback 當DOM中刪除元素時執行
  • attributeChangedCallback 當檢測到屬性發生更改或添加或刪除時執行(傳入3個參數)
    • attrName: 變化了的屬性名
    • oldVal: 屬性改變前的值
    • newVal: 屬性改變後的值
  • adoptedCallback 當元素已移至新文檔時
class CustomTitle extends HTMLElement {
    constructor() {
      //...
    }
  
    connectedCallback() {
      //...
    }
  
    disconnectedCallback() {
      //...
    }
    
    attributeChangedCallback(attrName, oldVal, newVal) {
      //...
    }
}
複製代碼

上面提到attributeChangedCallback 會監聽屬性值的變化,這裏要定義監聽屬性值的範圍,必須定義一個靜態方法用於返回監聽屬性的數組

class CustomTitle extends HTMLELement {
    constructor() {
      //...
    }
    
    static get observedAttributes() {
      return ['diabled']
    }
    
    attributeChangedCallback() {
      //...
    }
}
複製代碼

這裏我定義了 disabled 屬性用於被監聽,當它的值變化了,好比它的值爲 true

document.querySelector('custom-title').disabled = true
複製代碼

此時,attributeChangedCallback 被觸發,三個參數值分別爲 'disabled', false, true

定義自定義屬性

在自定義元素上定義自定義屬性,經過添加 getter 和 setter 函數向自定義元素上定義自定義屬性

class CustomTitle extends HTMLElement {
    static get observedAttributes() {
        return ['nbattribute']
    }
    
    get nbattribute() {
        return this.getAttribute('nbattribute')
    }
    
    set nbattribute(value) {
        this.setAttribute('nbattribute', value)
    }
}
複製代碼

若是是定義相似 disabled 這樣的布爾屬性值,若是值爲 true 時展現這個屬性值,false 時不展現

class CustomTitle extends HTMLElement {
    static get observedAttributes() {
        return ['boolattribute']
    }
    
    get boolattribute() {
        return this.hasAttribute('boolattribute')
    }
    
    set boolattribute(value) {
        if (value) {
            this.setAttribute('boolattribute', '')
        } else {
            this.removeAttribute('boolattribute')
        }
    }
}
複製代碼

設置還沒有定義的自定義元素的樣式

在頁面加載過程當中,JavaScript的加載須要時間,此時自定義元素還未定義,當頁面加載完成後,頁面的的從新佈局過程可能不是那麼友好,爲了解決這個問題,加入 :not(:defined) 僞類,設置一個大體的高度和漸變效果

custom-title:not(:defined) {
    display: block;
    height: 400px;
    opacity: 0;
    transition: opacity 0.5s ease-in-out;
}
複製代碼

瀏覽器支持狀況 caniuse

最新版的 FireFox,Safari,Chrome,使用 Chromium內核 重寫的Edge,IE(就別想了),另外能夠加入 polyfill 兼容老版本的瀏覽器

建立定製化功能的內置元素

所謂定製化功能的內質元素是指對 HTML 中已存在的元素進行定製化功能,對已存在的元素進行功能擴展。在原有的元素上掛上構造器,生命週期鉤子等功能特性。 建立定製的內置元素與徹底定製化的元素不一樣,區別在如下列子,接下來要對 Button 作功能擴展,首先須要定義一個類,繼承的不是 HTMLElement 而是 HTMLButtonElement

class PlasticButton extends HTMLButtonElement {
     constructor() {
        super()
    
        this.addEventListener('click', e => {
    	  // Do something 
        })
    }
}

// 在定義自定義元素時,須要加入 extends 參數
customElement.define('plastic-button', PlasticButton, { extends: 'button' })
複製代碼

在使用也有不一樣之處,在原有元素上使用 is 屬性指定擴展的元素

<button is="plastic-button"></button>
複製代碼

瀏覽器支持狀況 caniuse

最新版的 FireFox,Safari,Chrome,使用 Chromium內核 重寫的Edge,IE(就別想了),另外能夠加入 polyfill 兼容老版本的瀏覽器

Web Components 相關的庫

  • Hybrids is a UI library for creating Web Components with simple and functional API.
  • LitElement uses lit-html to render into the element's Shadow DOM and adds API to help manage element properties and attributes. Polymer provides a set of features for creating custom elements.
  • Slim.js is an opensource lightweight web component library that provides data-binding and extended capabilities for components, using es6 native class inheritance.
  • Stencil is an opensource compiler that generates standards-compliant web components.

參考

相關文章
相關標籤/搜索