將來的組件化標準 —— 淺嘗Web Components

原文地址css

前言

Web Components涉及到的內容仍是不少的,每一塊都有不少東西能夠講,國外的好多大佬已經產出了好多優秀的文章。 本文照常只是簡單瞭解大體內容而不進入深究,瞭解且會用便可,淺嘗輒止。html

簡介

Web Components自己不是一個規範,而是由W3C提出的另外4個規範的合集。這四個規範是:前端

下面咱們蜻蜓點水,簡單瞭解一個這四個東西。vue

HTML Template

以前的頁面開發常常的一個作法是把模板放在一個script標籤或者隱藏的div中,用的時候經過innerHTML取出,塞進數據, 而後放回頁面顯示。如今咱們能夠經過<template>標籤存放了。就像這樣:html5

<template id="mytemplate">
	<img src="" alt="great image">
  	<div class="comment"></div>
</template>
複製代碼

特性檢測

要特性檢測 <template>,能夠建立一個 template 元素並檢查它是否擁有 content 屬性:git

function supportsTemplate() {
	return 'content' in document.createElement('template');
}

if (supportsTemplate()) {
  	// 檢測經過!
} else {
  	// 使用舊的模板技術或庫。
}
複製代碼

激活模板

激活模板,即渲染出模板裏面的內容。激活模板最簡單的方法就是使用 document.importNode() 對模板的 .content 進行深拷貝。 .content 爲只讀屬性,關聯一個包含模板內容的 DocumentFragment。github

var t = document.querySelector('#mytemplate');
// 在運行時填充 src。
t.content.querySelector('img').src = 'logo.png';

var clone = document.importNode(t.content, true);
document.body.appendChild(clone);
複製代碼

特色

用 <template> 來包裹內容爲咱們提供了幾個重要屬性:web

  • 它的內容在激活以前一直處於惰性狀態。本質上,這些標記就是隱藏的 DOM,它們不會被渲染。ajax

  • 處於模板中的內容不會有反作用。腳本不會運行,圖片不會加載,音頻不會播放,...直到模板被使用。chrome

  • 內容不在文檔中。在主頁面使用 document.getElementById() 或 querySelector() 不會返回模板的子節點。

  • 模板可以被放置在任何位置,包括 <head>,<body>,或 <frameset>,而且任何可以出如今以上元素中的內容均可以放到模板中。 注意,"任何位置"意味着 <template> 可以安全的出如今 HTML 解析器不容許出現的位置... 幾乎能夠做爲任何內容模型的子節點, 它也能夠做爲 <table> 或 <select> 的子元素。

推薦閱讀

HTML Imports

以前在頁面引入另外一個頁面或片斷每每是經過iframe或者ajax異步加載,而如今咱們能夠這樣作:

在head中引入

<head>
	<link rel="import" href="/path/to/imports/stuff.html">
</head>
複製代碼

js中獲取

var content = document.querySelector('link[rel="import"]').import;
複製代碼

特性檢測

要檢測瀏覽器是否支持導入,可驗證 <link> 元素上是否存在 import:

function supportsImports() {
	return 'import' in document.createElement('link');
}

if (supportsImports()) {
  	// 支持導入
} else {
  	// 使用其餘方法加載文件
}
複製代碼

推薦閱讀

Shadow DOM

首先須要設置一下:打開開發者工具,f1打開設置(或右上角三個點),而後勾上Show user agent shadow DOM ——

而後再看下,video標籤是這樣的 ——

甚至一個普通的input ——

以前被隱藏掉的DOM部分就是shadow DOM。顧名思義,它是其宿主元素的影子,一般用來封裝組件的內部結構。

因此像video、audio甚至input都是用簡單的元素封裝的組件。

這讓我想到,咱們是否是能夠經過修改元素裏面的shadow DOM的樣式來改變該元素的樣式呢? 答案是 —— 是的,但也不徹底是...

從上圖audio標籤的結構和瀏覽器默認樣式能夠看到,咱們能夠像這樣修改對應的樣式:

audio::-webkit-media-controls {
	...
}
複製代碼

就像經過::-webkit-scrollbar改造瀏覽的滾動條樣式那樣,

因而,默認的audio樣式(新版chrome)——

small

通過改造後,能夠變成這樣——

small

然而並非全部樣式均可以這樣覆蓋改造,像pseudo="-internal-media-controls-loading-panel"這樣以"-internal-"開頭的是不能夠的。 因此這個作法仍是有很大侷限性的。

這是我試出來的,並沒發現相關標準或依據...😓

demo地址

這種作法自認爲只適合拿來玩玩而已,不適合投入到項目開發中去。一來是由於其侷限性太大,二來誰知道啥時候瀏覽器升級,這些標籤的內部結構就又變化了呢, 最重要的是shadow DOM是爲web Components而生的,與Custom Elements一塊兒是web Components的重要組成部分,並不是用於此「旁門左道」😆。

推薦閱讀

Custom Elements

自定義元素,首先有個硬性規定,自定義元素的命名中必需要有中劃線「-」,不然即是未知元素了。

自定義元素分爲兩種 ——

自特性主自定義元素(Autonomous custom elements)

不具有任何已有元素的,其樣式和行爲徹底自定義,如咱們要定義一個這樣的元素:

<flag-icon country="cn"></flag-icon>
複製代碼

經過給屬性country賦值來顯示對應的國旗。

js的基本結構是這樣的

class FlagIcon extends HTMLElement {
  	constructor() {
    	super();
    	this._countryCode = null;
  	}

  	static get observedAttributes() { return ["country"]; }

  	attributeChangedCallback(name, oldValue, newValue) {
	    // name will always be "country" due to observedAttributes
	    this._countryCode = newValue;
	    this._updateRendering();
  	}

  	connectedCallback() {
    	this._updateRendering();
  	}

  	get country() {
    	return this._countryCode;
  	}

  	set country(v) {
    	this.setAttribute("country", v);
  	}

  	_updateRendering() {
	    //...
  	}
}

//全局註冊該元素
customElements.define("flag-icon", FlagIcon);
複製代碼

註冊後,也經過js建立該元素

const flagIcon = document.createElement("flag-icon");
flagIcon.country = "cn";
document.body.appendChild(flagIcon);
複製代碼

自定義內置元素(Customized built-in elements)

繼承自已有元素,擁有已有元素的全部特性。

好比咱們自定義一個按鈕,集成普通按鈕全部的特性,可是當點擊的時候會有一個動效,就能夠這麼作 ——

class PlasticButton extends HTMLButtonElement {
  	constructor() {
    	super();

    	this.addEventListener("click", () => {
      		// 動效邏輯
    	});
  	}
}
複製代碼

不一樣的是,註冊時要加上一個參數

customElements.define("plastic-button", PlasticButton, { extends: "button" });
複製代碼

使用時也稍有不一樣

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

經過js定義元素,則是這樣

const plasticButton = document.createElement("button", { is: "plastic-button" });
plasticButton.textContent = "點我!";
document.body.appendChild(flagIcon);
複製代碼

生命週期

用過Vue、React等框架的同窗對生命週期應該不陌生。一樣,自定義元素有4個生命週期:

connectedCallback

元素首次被插入文檔DOM時觸發

disconnectedCallback

元素從文檔DOM中刪除時觸發

adoptedCallback

元素被移動到新的文檔時觸發

attributeChangedCallback

元素增長、刪除、修改自身屬性時觸發

推薦閱讀

來一個demo

評分組件相信你們都司空見慣了。照葫蘆畫瓢,我用原生js寫了一個Web Components 版的,簡單實現了該組件的基本功能。

demo截圖:

demo地址

推薦閱讀

總結

Web Components 爲前端組件化提供瞭解決方案,但用慣了Vue這樣的框架,仍是會發現Web Components 的問題, 好比

  • 瀏覽器的支持
  • 對樣式局部做用域的處理,每每js中包着一堆的CSS樣式,略顯臃腫
  • 父子、兄弟組件的通訊問題
  • 屬性都是字符串,須要額外的代碼作轉換和兼容
  • 沒有數據驅動,基本全是DOM操做

我的愚見,望大佬指點!🙏

相關文章
相關標籤/搜索