资讯专栏INFORMATION COLUMN

# Web Components 全揽

legendmohe / 3253人阅读

摘要:定制元素可以在原生元素外创建定制元素。此定制元素内部有一个加号按钮,一个减号按钮,一个显示当前值。此主题会在下一部分内介绍。定制元素的属性元素的属性被称为,对象内的属性被称为。做响应的同步处理。

Web Components 全揽

Web Components技术可以把一组相关的HTML、JS代码和CSS风格打包成为一个自包含的组件,只要使用大家熟悉的标签即可引入此组件。Web Components技术包括:

Custom Element

Shadow DOM

Template

HTML Import

四个分离而又互相关的四个构造块。其中核心的即使是Custom Element、Shadow DOM,顺便会讲到而Template是一个支持技术。
HTML Import曾经被Chrome加入但是随后和V0一起被废弃。这里也不会讨论它。

Custom Element 定制元素。

定制元素可以在原生元素外创建定制元素。定制元素是Web组件的一个基本构成块。可以在一个js文件内包含Custom Element需要的全部要素,包括HTML模板、CSS Style和ES6类。并使用一个HTML文件,引用此js文件从而可以使用定制元素。

假设我们创建Spin Button,定制元素标签为:


我们首先实现此定制元素,但是为了简单起见,晚一点才看它的属性。此定制元素内部有一个加号按钮,一个减号按钮,一个span显示当前值。那么只需要把这个HTML模板组织、风格和代码组合在一个文件内:

var template = `
    1
    
`
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了:



你可以看到执行在浏览器内的界面上的两个按钮和一个span。创建一个定制元素有几个要点:

新的JS定制类需要继承于类HTMLElement

回调connectedCallback提供一个生命周期事件,当定制元素成功挂接到DOM后,会调用此回调,可以在此回调代码内加入自己的定制内容

代码中的this,指向了此定制元素本身,因此可以通过this.innerHTML设置本定制元素的内部DOM

这样,我们创建了一个独特的定制元素,这个元素不在原生的浏览器标签内。

定制元素就是这样创建了,并且对于使用者来说,只要通过熟悉的元素标签,即可引用一组带有定制风格、操作和界面的组件了。

但是此时的定制元素有一个问题,就是它内部定义的风格,不仅仅会影响内部的元素,也会泄露到外部导致文档也被影响,从而引发我们不希望的边际效应。比如在index.html内如果在文件尾部加入这样的文本:

black

你会发现black文本不是默认的颜色,而是红色,这样红色来自于定制元素内部的风格定义代码。如果希望隔离组件内的风格定义,那么可以使用Shaddow DOM技术。此主题会在下一部分内介绍。

Shadow DOM

Web建站使用组件技术有比较长的历史了,这个技术一直以来都有一个挑战,就是如何让一个页面可以使用第三方控件,但是不会被此组件使用的CSS风格所影响。解决方案是CSS可以局部化。想要组件内部的风格不会影响到外部,办法就是使用Shadow DOM。Shadow DOM创建了一个隔离区,在这个隔离区内的DOM是独立的,这意味着:

内部DOM Tree不会被外部文档访问到

也不会被外部的风格设置影响

内部的风格也不会影响到外部文档

我们拿前一个案例代码做实验,看看如果使用这个技术特性。

使用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 = `
    1
    
`
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查询当前支持状态。

ref

Posts of wb

https://alligator.io/web-comp...

Custom Elements v1: Reusable Web Components

https://developers.google.com...
*3. web-components-examples
https://github.com/mdn/web-co...

Firefox 63 – Tricks and Treats!

https://hacks.mozilla.org/201...

HTML Web Component using Plain JavaScript

https://www.codementor.io/ayu...
6. Doing something with Web Components
https://medium.com/@dalaidunc...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99639.html

相关文章

  • Javascript模块全揽

    摘要:要求模块编写必须在真正的代码之外套上一层规定的代码包装,样子看起来是这样的模块代码通过传递一个签名为的回调函数给函数,就可以把需要注入的变量和函数注入到模块代码内。 之前写的文章急速Js全栈教程得到了不错的阅读量,霸屏掘金头条3天,点赞过千,阅读近万,甚至还有人在评论区打广告,可见也是一个小小的生态了;)。看来和JS全栈有关的内容,还是有人颇有兴趣的。 showImg(https://...

    lily_wang 评论0 收藏0
  • PHPer 为什么会被 Javaer 鄙视?

    摘要:最近看了知乎上的一个话题在工作中,为什么程序员常常瞧不起程序员个人从业多年,用过的后端语言,如果你非要让我说哪种语言好,我会说凡是宏哥说的都是对的,凡是宏哥提倡的都要坚持。只有真正的理解了宏哥思想才可以洞穿一切,走出空谷。 最近看了知乎上的一个话题「在工作中,为什么 Java 程序员常常瞧不起 PHP 程序员?」 个人从业多年,用过的后端语言 ASP、ASP.NET、Java、PHP、...

    jasperyang 评论0 收藏0
  • PHPer 为什么会被 Javaer 鄙视?

    摘要:最近看了知乎上的一个话题在工作中,为什么程序员常常瞧不起程序员个人从业多年,用过的后端语言,如果你非要让我说哪种语言好,我会说凡是宏哥说的都是对的,凡是宏哥提倡的都要坚持。只有真正的理解了宏哥思想才可以洞穿一切,走出空谷。 最近看了知乎上的一个话题「在工作中,为什么 Java 程序员常常瞧不起 PHP 程序员?」 个人从业多年,用过的后端语言 ASP、ASP.NET、Java、PHP、...

    zhoutk 评论0 收藏0
  • Web Components(一)入门

    摘要:随着页面中相同或类似的增加,使得代码冗余度增加,的重用性问题日益彰显。影子使得这些与主文档的保持分离。分离的原因是如果复杂页面没有很好的组织结构,样式容易覆盖。 为什么 Web Components? 早期在我们构建web页面时,基本上都是通过组合HTML提供的标签来实现的,再简单点我们还可以拷贝黏贴bootstrap的css代码。随着页面中相同或类似UI的增加,使得代码冗余度增加,U...

    calx 评论0 收藏0

发表评论

0条评论

legendmohe

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<