
还记得当document.querySelector最起初被广泛的被浏览器支持以及结束了无处不在的JQuery。这最后给我们提供了一个原生的方式,虽然JQuery已经提供了好久。我认为这相同即将出现在像Angular和React这的前端框架身上。
这种框架可以帮助我们去做一些做不到的事情,比如建立可以复用的后端组件,但是这种应该付出复杂度、专属语法、性能消耗的损失。但是这种即将受到改变。
现代浏览器的API已经升级到你不应该使用一个框架就可以去建立一个可复用的模块。CustomElement和ShadowDOM都可以让你去创造可复用的组件。
最早在2011年,WebComponents就早已是一个只应该使用HTML、CSS、Java就可以建立可复用的模块被介绍给你们。这也意味着你可以不使用类似React和Angular的框架就可以成就组件。甚至,这些模块可以无缝的接入到这种框架中。
这样久以来第一次,我们可以只使用HTML、CSS、Java来建立可以在任何现代浏览器运行的可复用模块。WebComponents现在终于被主要的浏览器的较新版本所支持。
Edge将会在接出来的19版本提供支持。而针对这些旧的版本可以使用polyfill兼容至IE11.这意味着你可以在现今基本上任何浏览器或者移动端使用WebComponents。
创造一个你定制的HTML标签,它将会继承HTM元素的所有属性,并且你可在任何支持的浏览器中借助简单的采用一个。所有的HTML、CSS、Java将会在模块内部局部定义。这个模块在你的浏览器开发软件中显示为一个单独个HTML标签,并且它的风格和行为都是完全在模块内进行,不应该工作区,框架和一些前置的转化。
让我们来看一些WebComponents的一些主要功能。
自定义元素
自定义元素是简洁的用户自定义HTML元素。它们借助使用CustomElementRegistry来定义。
要注册一个新的元素,通过window.customElements中一个叫define的方式来获得注册的例子。
window.customElements.define('my-element',MyElement);
方法中的第一个参数定义了新成就元素的标签名,我们可以更加简单的直接使用
<my-element></my-element>
为了防止和native标签冲突,这里强制使用中划线来连接。这里的MyElement的构造变量必须使用ES6的class,这让Java的class不像以前面向对象class那么让人苦恼。同样的,如果一个Object和Proxy可以被使用来给自定义元素进行简洁的数据绑定。但是,为了确保你的原生HTML元素的拓展性并确保元素继承了整个DOMAPI,需要使用这个限制。让我们写一个这个自定义元素class
classMyElementextendsHTMLElement{
constructor(){
super();
}
connectedCallback(){
//heretheelementhasbeeninsertedintotheDOM
}
}
这个自定义元素的class就似乎一个常规的继承自nativeHTML元素的class。在它的构造函数中有一个叫connectedCallback额外添加的方式,当这个元素被插入DOM树的之后将要触发这个办法。你可以把这个办法与React的componentDidMount方法。
一般来说,我们必须在connectedCallback之后进行元素的设定。因为这是惟一可以确认所有的属性和子元素都早已可用的方法。构造变量通常是用来初始化状况和修改ShadowDOM。
元素的构造变量和connectCallback的差别是,当时一个元素被建立时(好比document.)将会读取构造变量,而当一个元素终于被插入到DOM中时会调用connectedCallback,例如在即将声明并被解读的文档中,或者使用document.body.添加。
你同样可以用过调用customElements.get(‘my-element’)来获得这个元素构造变量的引用,从而构造元素。前提是你终于通过customElement.define()去注册。然后你可以使用newelement()来代替document.()去实例一个元素。
customElements.define('my-element',classextendsHTMLElement{...});
...
constel=customElements.get('my-element');
constmyElement=newel();//sameasdocument.('my-element');
document.body.(myElement);
与connectedCallback相对应的则是disconnectCallback,当元素从DOM中移除的之后将要调用它。但是要记住,在客户关掉浏览器以及浏览器tab的之后,不会调用这个办法。还有adoptedCallback,当元素通过读取document.adoptNode(element)被引入到文档时将要被调用,虽然到如今为止,我还没有遇到这个办法被调用的之后。
另一个有用的生命周期原则是attributeChangedCallback,每当将属性添加到observedAttributes的字段中时,就会读取这个变量。这个步骤调用时两个参数分别为旧值和新值。
classMyElementextendsHTMLElement{
staticgetobservedAttributes(){
return['foo','bar'];
}
attributeChangedCallback(attr,oldVal,newVal){
switch(attr){
case'foo':
//dosomethingwith'foo'attribute
case'bar':
//dosomethingwith'bar'attribute
}
}
}
这个方式唯有当被保存在observedAttributes数组的属性改变时,就如这个示例中的foo和bar,被改变就会调用,其他属性改变则不会。属性主要用在声明元素的初始配置,状态。理论上借助序列化可以将复杂值释放给属性,但是这种会妨碍性能,并且你可以直接调用模块的方式,所以不必须这么做。但是一旦你期望像React和Angular这样的框架提供属性的绑定,那你可以看一下。Polymer。
生命周期变量的排序
顺序如下:
constructor->attributeChangedCallback->connectedCallback
为什么attributeChangedCallback要在connectedCallback之前执行呢?
回想一下,web模块上的属性主要拿来初始化配置。这意味着当组件被插入DOM时,这些配置应该可以被访问了。因此attributeChangedCallback要在connectedCallback之前执行。这意味着你应该按照这种属性的值,在ShadowDOM中配置任何节点,那么你应该在构造变量中引用某些节点,而不是在connectedCallback中引用他们。
比如,如果你有一个ID为container的模块,并且你应该在按照属性的颠覆来决定能否给这个元素添加一个红色的背景,那么你可以在构造变量中引用这个元素,以便它可以在attributeChangedCallback中使用:
constructor(){
this.container=this.shadowRoot.querySelector('#container');
}
attributeChangedCallback(attr,oldVal,newVal){
if(attr==='disabled'){
if(this.hasAttribute('disabled'){
this.container.style.background='#808080';
}
else{
this.container.style.background='#ffffff';
}
}
}
即使你经常等到connectedCallback再去创建this.container。然后在第一时间调用attributeChangedCallback,它而是不尅用的。因此虽然你需要尽或许的延迟你组件的connectedCallback,但在这些状况下是不也许的。
同样重要的是,你可以在模块使用customElement.define()之前去使用它。当改元素发生在DOM或者被插入到DOM,而还没有被注册时。它将要是一个HTMLUnkonwElement的例子。浏览器即将这种处理未知的元素,你可以像处理其它元素一样与它交互,除此之前,它将不会有任何方法和默认样式。
但是当通过使用customElement.define()去定义它时,并可使用类来定义增加它webcomponents可以删除吗,这个过程被称为更新。当使用customElement.whenDefined升级元素时,可以调用回调,并会返回一个promise。当这个元素被升级时。
customElements.whenDefined('my-element')
.then(()=>{
//my-elementisnowdefined
})WebComponent的公共API
比如很多生命周期原则,你还可以定义可以从内部调用的方式,这针对使用React和Angular等框架至今是不可行的。例如你可以定义一个名为doSomething的方法:
classMyElementextendsHTMLElement{

...
doSomething(){
//dosomethinginthismethod
}
}
但是你可以在内部使用它
constelement=document.querySelector('my-element');
element.doSomething();
在你的元素上定义的任何方法,都会变成其公共Java的一个别。通过某些方法,你可以给元素的属性提供setter来推动数据绑定。例如在元素的HTML中展现设置的属性值。由于本质上不可以将给属性修改比如字符串以外的值,所以需要讲像对象那样的复杂之成为属性释放给自定义元素。
比如生命组件的初始状况,属性还可以用于对应属性的值,以便将元素的Java状态反应到DOM的体现中。input元素的disabled属性就是一个很高的举例:
<inputname="name">
constinput=document.querySelector('input');
input.disabled=true;
在将input的disabled的属性修改为true后,改变也会相应的体现到disabled属性上。
<inputname="name"disabled>
通过setter可以很容易的将property反应到attribute上。
classMyElementextendsHTMLElement{
...
setdisabled(isDisabled){
if(isDisabled){
this.setAttribute('disabled','');
}
else{
this.removeAttribute('disabled');
}
}
getdisabled(){
returnthis.hasAttribute('disabled');
}
}
当attribute改变后必须执行这些操作时,将其添加到observedAttributes数组中。作为一种性能改进,只有在这被列举出的属性就会监测他们的改变。无论这个attribute什么之后改变了,都会调用attributeChangedCallback,参数分别是当前值和新的值。
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/sanxing/article-120724-1.html
超级期待啊
家电使用20年还杠杠的只能说明设计过度
才能具备基本的判断分析能力