Web Components技术能够把一组相关的HTML、JS代码和CSS风格打包成为一个自包含的组件,只要使用你们熟悉的标签便可引入此组件。Web Components技术包括:html
四个分离而又互相关的四个构造块。其中核心的即便是Custom Element、Shadow DOM,顺便会讲到而Template是一个支持技术。
HTML Import曾经被Chrome加入可是随后和V0一块儿被废弃。这里也不会讨论它。git
定制元素能够在原生元素外建立定制元素。定制元素是Web组件的一个基本构成块。能够在一个js文件内包含Custom Element须要的所有要素,包括HTML模板、CSS Style和ES6类。并使用一个HTML文件,引用此js文件从而可使用定制元素。github
假设咱们建立Spin Button,定制元素标签为:web
<spin-button value=“100” step="10" min="50" max="150"></spin-button>
咱们首先实现此定制元素,可是为了简单起见,晚一点才看它的属性。此定制元素内部有一个加号按钮,一个减号按钮,一个span显示当前值。那么只须要把这个HTML模板组织、风格和代码组合在一个文件内:浏览器
var template = ` <button inc>+</button><span>1</span><button dec>-</button> <style> span{color:red;} *{font-size:2rem;} </style> ` class SpinButton extends HTMLElement{ connectedCallback(){ this.innerHTML = template var b1 = this.querySelector('[inc]') var b2 = this.querySelector('[dec]') var s = this.querySelector('span') var i = 1 b1.onclick = function(){ s.innerHTML = i++ } b2.onclick = function(){ s.innerHTML = i-- } } } customElements.define('spin-button',SpinButton)
而且建立一个index.html文件加载此文件,便可使用新的定制元素spin-button了:app
<script src="./spin.js"></script> <spin-button></spin-button>
你能够看到执行在浏览器内的界面上的两个按钮和一个span。建立一个定制元素有几个要点:函数
这样,咱们建立了一个独特的定制元素,这个元素不在原生的浏览器标签内。网站
定制元素就是这样建立了,而且对于使用者来讲,只要经过熟悉的元素标签,便可引用一组带有定制风格、操做和界面的组件了。this
可是此时的定制元素有一个问题,就是它内部定义的风格,不只仅会影响内部的元素,也会泄露到外部致使文档也被影响,从而引起咱们不但愿的边际效应。好比在index.html内若是在文件尾部加入这样的文本:google
<span>black</span>
你会发现black文本不是默认的颜色,而是红色,这样红色来自于定制元素内部的风格定义代码。若是但愿隔离组件内的风格定义,那么可使用Shaddow DOM技术。此主题会在下一部份内介绍。
Web建站使用组件技术有比较长的历史了,这个技术一直以来都有一个挑战,就是如何让一个页面可使用第三方控件,可是不会被此组件使用的CSS风格所影响。解决方案是CSS能够局部化。想要组件内部的风格不会影响到外部,办法就是使用Shadow DOM。Shadow DOM建立了一个隔离区,在这个隔离区内的DOM是独立的,这意味着:
咱们拿前一个案例代码作实验,看看若是使用这个技术特性。
使用Shadow DOM的关键,是首先建立一个Shadow Node,整个组件内部的HTML片断都插入到此节点内,而不是直接使用组件的innerHTML。咱们能够在组件对象的构造器内执行此代码:
class SpinButton extends HTMLElement{ constructor(){ super() var shadow = this.attachShadow({mode:'open'}) var t = document.createElement('template') t.innerHTML = template shadow.appendChild(t.content.cloneNode(true)) } }
执行后,你会发现span的风格再也不影响组件以外的标签。看起来仍是很简单的,只要把你原本须要构造的HTML内部DOM插入到shadow节点内便可。
元素的属性被称为Attribute,JS对象内的属性被称为Property。代码惯例上每个Attribute都会有JS对象的一个Property对应。为了方便,咱们但愿添加的Attribute能够和JS内的Property同步。就是说,若是有人经过HTML DOM API修改了Attribute,那么我但愿对于的JS属性会被同步修改;反之亦然,有人修改了Property,那么这个修改能够会同步修改到对应的Attribute。
咱们以spin-button的value属性为例。定义一个普通的Property的方法是经过get/set关键字,好比定义value:
get value(){} set value(newValue){}
随后就可使用object.value
访问此属性值,或者经过object.value = newValue
为属性设置新值。能够在两个函数内经过代码设置和Attribute同步:
get value(){ return this.getAttribute('value') || 1 } set value(v){ this.setAttribute('value',v) }
这样代码内经过对属性value的访问,最后都会致使对Attribute的访问。若是有代码对Attribute访问,如何修改Attribute的同时同步更新Property呢。这就须要利用HTMLElement提供的生命周期方法了:
static get observedAttributes() { return ['value']; } attributeChangedCallback(name, oldValue, newValue) { switch (name) { case 'value': break; } }
方法observedAttributes听过返回值声明须要观察的属性,这样就能够在指定属性清单发生更新时经过另外一个生命周期方法attributeChangedCallback
,通知代码变化的状况。作响应的同步处理。整合后的代码以下:
var template = ` <button inc>+</button><span>1</span><button dec>-</button> <style> span{color:red;} *{font-size:2rem;} </style> ` class SpinButton extends HTMLElement{ constructor(){ super() var shadow = this.attachShadow({mode:'open'}) var t = document.createElement('template') t.innerHTML = template shadow.appendChild(t.content.cloneNode(true)) var b1 = shadow.querySelector('[inc]') var b2 = shadow.querySelector('[dec]') this.s = shadow.querySelector('span') var i = 1 var that = this b1.onclick = function(){ that.s.innerHTML = ++that.value } b2.onclick = function(){ that.s.innerHTML = -- that.value } } static get observedAttributes() { return ['value']; } attributeChangedCallback(name, oldValue, newValue) { switch (name) { case 'value': this.s.innerHTML = newValue break; } } get value(){ return this.getAttribute('value') || 1 } set value(v){ this.setAttribute('value',v) } } customElements.define('spin-button',SpinButton)
Web Components的关键构成技术包括Custom Element和Shadow DOM,最先在Chrome实现,第一个版本被称为V0可是其余浏览器没有跟进,所以逐步被废弃。本文讨论的是V1版本。Firefox也已经实现了V1版本。
能够在网站Whatcaniuse查询当前支持状态。
https://alligator.io/web-comp...
https://developers.google.com...
*3. web-components-examples
https://github.com/mdn/web-co...
https://hacks.mozilla.org/201...
https://www.codementor.io/ayu...
6. Doing something with Web Components
https://medium.com/@dalaidunc...