是个什么样的东西,outerHTML完成代码

HTML 自定义元素教程

2017/06/22 · HTML5 ·
自定义元素

原稿出处:
阮一峰   

零件是 Web 开发的主旋律,现在的紧俏是 JavaScript 组件,然则 HTML
组件未来也许更有期待。

本文就介绍 HTML 组件的基础知识:自定义元素(custom elements)。

亚洲必赢官网 1

一、浏览器处理

大家一般都施用标准的 HTML 元素。

XHTML

<p>Hello World</p>

1
<p>Hello World</p>

地点代码中,“

“就是专业的 HTML 元素。

若果使用非标准的自定义元素,会有怎样结果?

XHTML

<greeting>Hello World</greeting>

1
<greeting>Hello World</greeting>

地点代码中,`就是非标准元素,浏览器不认识它。这段代码的[运行结果](http://jsbin.com/rifozonomu/edit?html,output)是,浏览器照常显示Hello World`,那表达浏览器并从未过滤那一个因素。

亚洲必赢官网 2

今昔,为自定义元素加上样式。

JavaScript

greeting { display: block; font-size: 36px; color: red; }

1
2
3
4
5
greeting {
  display: block;
  font-size: 36px;
  color: red;
}

运行结果如下。

亚洲必赢官网 3

接着,使用脚本操作这些因素。

JavaScript

function customTag(tagName, fn){ Array
.from(document.getElementsByTagName(tagName)) .forEach(fn); } function
greetingHandler(element) { element.innerHTML = ‘你好,世界’; }
customTag(‘greeting’, greetingHandler);

1
2
3
4
5
6
7
8
9
10
11
function customTag(tagName, fn){
  Array
    .from(document.getElementsByTagName(tagName))
    .forEach(fn);
}
 
function greetingHandler(element) {
  element.innerHTML = ‘你好,世界’;
}  
 
customTag(‘greeting’, greetingHandler);

运作结果如下。

亚洲必赢官网 4

那注解,浏览器对待自定义元素,就像是对待专业元素一样,只是没有默许的样式和表现。那种处理格局是写入
HTML5
标准的。

“User agents must treat elements and attributes that they do not
understand as semantically neutral; leaving them in the DOM (for DOM
processors), and styling them according to CSS (for CSS processors),
but not inferring any meaning from them.”

地点这段话的意思是,浏览器必须将自定义元素保留在 DOM
之中,但不会其余语义。除此之外,自定义元素与业内元素都同样。

实质上,浏览器提供了一个HTMLUnknownElement对象,所有自定义元素都是该目的的实例。

JavaScript

var tabs = document.createElement(‘tabs’); tabs instanceof
HTMLUnknownElement // true tabs instanceof HTMLElement // true

1
2
3
4
var tabs = document.createElement(‘tabs’);
 
tabs instanceof HTMLUnknownElement // true
tabs instanceof HTMLElement // true

位置代码中,tabs是一个自定义元素,同时继续了HTMLUnknownElementHTMLElement接口。

Web Components 是个什么样的东西

2016/09/04 · HTML5,
JavaScript · Web
Components

初稿出处: teabyii   

前者组件化那么些大旨相关的内容已经火了很久很久,angular 刚出去时的
Directive 到 angular2 的 components,还有 React 的components
等等,无一不是前端组件化的一种落成和追究,不过提上议程的 Web Components
标准是个如何的事物,相关的一部分框架或者类库,如 React,Angular2,甚至是
x-tag,polymer 现在落实的组件化的事物和 Web Components
标准差别在何地?我花时间努力地把现有的 W3C Web
Components
文档看了下,然后坚强地写下这几个记录。

首先大家须求精晓,Web Components 包蕴了多少个部分:

  • Custom Elements
  • HTML Imports
  • HTML
    Templates
  • Shadow DOM

那四有的有机地构成在一起,才是 Web Components。

可以用自定义的竹签来引入组件是前者组件化的功底,在页面引用 HTML 文件和
HTML 模板是用以襄助编写组件视图和零部件资源管理,而 Shadow DOM
则是隔离组件间代码的争持和震慑。

上边分别是每一部分的笔记内容。

HTML imports 入门

2015/02/10 · HTML5 ·
HTML,
imports

本文由 伯乐在线 –
XfLoops
翻译,周进林
校稿。未经许可,禁止转发!
英文出处:webcomponents.org。欢迎加入翻译组。

Template、Shadow
DOM及Custom
Elements 让您创建UI组件比此前更便于了。然而像HTML、CSS、JavaScript那样的资源依旧要求一个个地去加载,那是很没成效的。

删除重复信赖也并不简单。例如,现在加载jQuery
UI或Bootstrap就要求为JavaScript、CSS及Web
Fonts添加单独的标签。倘使你的Web
组件应用了两次三番串的借助,那事情就变得尤为复杂。

HTML 导入让你以一个联合的HTML文件来加载这几个资源。

裁减DOM数可以加速浏览器的在分析页面进度中DOM Tree和render
tree的营造,从而提升页面品质。为此我们得以把页面中这几个首屏渲染不可知的片段HTML暂存在TextArea中,等成功渲染后再处理那有些HTML来达到那么些目的。
要把TextArea
中暂存的HTML内容添加到页面中,使用要素的outerHTML属性是最简易方便的了,可是在DOM标准中并没有定义outerHTML,协理的浏览器有IE6+,safari,
operal和 Chrome,经测试FF4.0-
中还不扶助。所以大家就来贯彻一个可以跨浏览器的outerHTML。
outerHTML 就是收获或设置包涵元素标签自己在内的html。下边是促成代码:

二、HTML import

有了自定义元素,就足以写出语义性万分好的 HTML 代码。

XHTML

<share-buttons> <social-button type=”weibo”> <a
href=”…”>微博</a> </social-button> <social-button
type=”weixin”> <a href=”…”>微信</a>
</social-button> </share-buttons>

1
2
3
4
5
6
7
8
<share-buttons>
  <social-button type="weibo">
    <a href="…">微博</a>
  </social-button>
  <social-button type="weixin">
    <a href="…">微信</a>
  </social-button>
</share-buttons>

上边的代码,一眼就能来看语义。

如果将`元素的样式与脚本,封装在一个 HTML
文件
share-buttons.html`之中,这几个元素就可以复用了。

选拔的时候,先引入share-buttons.html

<link rel=”import” href=”share-buttons.html”>

1
<link rel="import" href="share-buttons.html">

下一场,就可以在网页中利用“了。

XHTML

<article> <h1>Title</h1> <share-buttons/> …
… </article>

1
2
3
4
5
<article>
  <h1>Title</h1>
  <share-buttons/>
  … …
</article>

HTML imports
的越来越多用法可以参见教程(1,2)。方今只有Chrome 浏览器辅助那么些语法。

Custom Elements

使用HTML导入

是个什么样的东西,outerHTML完成代码。为加载一个HTML文件,你须要充实一个link标签,其rel属性为import,herf属性是HTML文件的门道。例如,如果您想把component.html加载到index.html:

index.html

XHTML

<link rel=”import” href=”component.html” >

1
<link rel="import" href="component.html" >

你可以往HTML导入文本(译者注:本文将“ the imported
HTML”译为“HTML导入文本”,将“the original
HTML”译为“HTML主文件”。例如,index.html是HTML主文件,component.html是HTML导入文本。)添加此外的资源,包含剧本、样式表及字体,就跟往普通的HTML添加资源均等。

component.html

XHTML

<link rel=”stylesheet” href=”css/style.css”> <script
src=”js/script.js”></script>

1
2
<link rel="stylesheet" href="css/style.css">
<script src="js/script.js"></script>

doctype、html、 head、 body那一个标签是不需求的。HTML
导入会登时加载要导入的文档,解析文档中的资源,借使有脚本的话也会立马执行它们。

复制代码 代码如下:

三、Custom Elements 标准

HTML5 标准规定了自定义元素是合法的。然后,W3C
就为自定义元素制定了一个单独的 Custom Elements
标准。

它与其余多个正经放在一起—- HTML Imports,HTML Template、Shadow
DOM—-统称为 Web
Components
规范。如今,这几个专业唯有 Chrome
浏览器支持。

亚洲必赢官网 5

Custom Elements
标准对自定义元素的名字做了限制。

“自定义元素的名字务必带有一个破折号(-)所以都是正确的名字,而和“是不得法的。那样的限量使得
HTML 解析器可以辨认那几个是正规元素,哪些是自定义元素。”

亚洲必赢官网 6

小心,一旦名字之中使用了破折号,自定义元素就不是HTMLUnknownElement的实例了。

JavaScript

var xTabs = document.createElement(‘x-tabs’); xTabs instanceof
HTMLUnknownElement // false xTabs instanceof HTMLElement // true

1
2
3
4
var xTabs = document.createElement(‘x-tabs’);
 
xTabs instanceof HTMLUnknownElement // false
xTabs instanceof HTMLElement // true

Custom Elements 标准规定了,自定义元素的定义可以利用 ES6
class语法。

JavaScript

// 定义一个 class MyElement extends HTMLElement {…}
window.customElements.define(‘my-element’, MyElement);

1
2
3
// 定义一个
class MyElement extends HTMLElement {…}
window.customElements.define(‘my-element’, MyElement);

地点代码中,原生的window.customElements对象的define艺术用来定义
Custom
Element。该措施接受八个参数,第三个参数是自定义元素的名字,第一个参数是一个
ES6 的class

这个class使用getset主意定义 Custom Element 的某个属性。

JavaScript

class MyElement extends HTMLElement { get content() { return
this.getAttribute(‘content’); } set content(val) {
this.setAttribute(‘content’, val); } }

1
2
3
4
5
6
7
8
9
class MyElement extends HTMLElement {
  get content() {
    return this.getAttribute(‘content’);
  }
 
  set content(val) {
    this.setAttribute(‘content’, val);
  }
}

有了这一个概念,网页之中就足以插入“了。

JavaScript

<my-element content=”Custom Element”> Hello </my-element>

1
2
3
<my-element content="Custom Element">
  Hello
</my-element>

拍卖脚本如下。

JavaScript

function customTag(tagName, fn){ Array
.from(document.getElementsByTagName(tagName)) .forEach(fn); } function
myElementHandler(element) { element.textConent = element.content; }
customTag(‘my-element’, myElementHandler);

1
2
3
4
5
6
7
8
9
10
11
function customTag(tagName, fn){
  Array
    .from(document.getElementsByTagName(tagName))
    .forEach(fn);
}
 
function myElementHandler(element) {
  element.textConent = element.content;
}
 
customTag(‘my-element’, myElementHandler);

运作结果如下。

亚洲必赢官网 7

ES6 Class 的一个便宜是,可以很不难地写出继承类。

JavaScript

class MyNewElement extends MyElement { // … }
customElements.define(‘my-new-element’, MyNewElement);

1
2
3
4
5
class MyNewElement extends MyElement {
  // …
}
 
customElements.define(‘my-new-element’, MyNewElement);

明天的学科就到那边,更多用法请参考谷歌(谷歌)的官方教程。

概述

Custom Elements 顾名思义,是提供一种艺术让开发者可以自定义 HTML
元素,包涵特定的结缘,样式和表现。援救 Web Components
标准的浏览器会提供一二种 API
给开发者用于成立自定义的因素,或者伸张现有元素。

这一项标准的草案还处在不平静的动静,时有更新,API
还会有所变化,上边的笔记以 Cutsom Elements
2016.02.26
这几个版本为准,因为在最新的 chrome 浏览器已经是足以干活的了,那样可以运用
demo 来做尝试,最终我会再不难写一下新颖文档和这几个的分别。

实践顺序

浏览器解析HTML文档的主意是线性的,那就是说HTML顶部的script会比底部先举办。并且,浏览器寻常会等到JavaScript代码执行完结后,才会随之分析前面的代码。

为了不让script 妨碍HTML的渲染,你可以在标签中添加async或defer属性(或者您也可以将script 标签放到页面的尾部)。defer 属性会延迟脚本的实施,直到所有页面解析完成。async 属性让浏览器异步地履行脚本,从而不会妨碍HTML的渲染。那么,HTML
导入是怎么工作的吗?

HTML导入文本中的脚本就跟含有defer属性一样。例如在底下的以身作则中,index.html会先实施script1.js和script2.js
,然后再实施script3.js。

index.html

XHTML

<link rel=”import” href=”component.html”> // 1.
<title>Import Example</title> <script
src=”script3.js”></script> // 4.

1
2
3
<link rel="import" href="component.html"> // 1.
<title>Import Example</title>
<script src="script3.js"></script>        // 4.

component.html

XHTML

<script src=”js/script1.js”></script> // 2. <script
src=”js/script2.js”></script> // 3.

1
2
<script src="js/script1.js"></script>     // 2.
<script src="js/script2.js"></script>     // 3.

1.在index.html 中加载component.html并等待执行

2.执行component.html中的script1.js

3.执行完script1.js后执行component.html中的script2.js

4.履行完 script2.js继而执行index.html中的script3.js

注意,如果给link[rel=”import”]添加async属性,HTML导入会把它当作含有async属性的脚本来对待。它不会等待HTML导入文本的执行和加载,那象征HTML
导入不会妨碍HTML主文件的渲染。那也给升迁网站质量带来了可能,除非有任何的本子依赖于HTML导入文本的举办。

if(typeof HTMLElement !== “undefined” && !(“outerHTML” in
HTMLElement.prototype)) {
//console.log(“defined outerHTML”);
HTMLElement.prototype.__defineSetter__(“outerHTML”,function(str){
var fragment = document.createDocumentFragment();
var div = document.createElement(“div”);
div.innerHTML = str;
for(var i=0, n = div.childNodes.length; i<n; i++){
fragment.appendChild(div.childNodes[i]);
}
this.parentNode.replaceChild(fragment, this);
});
//
HTMLElement.prototype.__defineGetter__(“outerHTML”,function(){
var tag = this.tagName;
var attributes = this.attributes;
var attr = [];
//for(var name in attributes){//遍历原型链上成员
for(var i=0,n = attributes.length; i<n; i++){//n指定的习性个数
if(attributes[i].specified){
attr.push(attributes[i].name + ‘=”‘ + attributes[i].value + ‘”‘);
}
}
return ((!!this.innerHTML) ?
‘<‘ + tag + ‘ ‘ + attr.join(‘
‘)+’>’+this.innerHTML+'</’+tag+’>’ :
‘<‘ + tag + ‘ ‘ +attr.join(‘ ‘)+’/>’);
});
}

四、参考链接

  • John Negoita, Extending HTML by Creating Custom
    Tags
  • StackOverflow, Are custom elements valid
    HTML5?
  • Eric Bidelman, Custom Elements v1: Reusable Web
    Components

 

1 赞 1 收藏
评论

亚洲必赢官网 8

registerElement

率先,我们得以品味在 chrome 控制台输入
HTMLInputElement,可以看出是有如此一个东西的,那一个领悟为 input DOM
元素实例化时的构造函数,基础的是 HTMLElement

Web Components 标准指出提供这么一个接口:

JavaScript

document.registerElement(‘x-foo’, { prototype:
Object.create(HTMLElement.prototype, { createdCallback: { value:
function() { … } }, … }) })

1
2
3
4
5
6
7
8
document.registerElement(‘x-foo’, {
  prototype: Object.create(HTMLElement.prototype, {
    createdCallback: {      
      value: function() { … }
    },
    …
  })
})

您可以使用 document.registerElement 来注册一个标签,标准中为了提供
namesapce 的支持,幸免顶牛,规定标签类型(也可以驾驭为名字)必要运用 -
连接。同时,不可以是以下这一部分:

  • annotation-xml
  • color-profile
  • font-face
  • font-face-src
  • font-face-uri
  • font-face-format
  • font-face-name
  • missing-glyph

其次个参数是标签相关的配备,紧倘使提供一个 prototype,那一个原型对象是以
HTMLElement 等的原型为根基成立的目标。然后您便足以在 HTML
中去采纳自定义的标签。如:

XHTML

<div> <x-foo></x-foo> </div>

1
2
3
<div>
  <x-foo></x-foo>
</div>

是或不是嗅到了 React 的味道?好吧,React 说它自己根本不是做那几个事情的。

跨域导入

从根本上说,HTML导入是无法从任何的域名导入资源的。

比如说,你不可以从向 
导入HTML
文件。为了绕过那些范围,可以使用CORS(跨域资源共享)。想了解CORS,请看那篇小说。

代码表达:
1
代码中第一条件判断来监测浏览器是不是帮衬outerHTML以幸免覆盖浏览器原生的兑现。
2 “__defineSetter__”,”__defineGetter__”
是firefox浏览器私有方面。分别定义当设置属性值和得到属性要实践的操作。
3 在”__defineSetter__”
“outerHTML”中为了防止插入页面中元素过多导致频仍暴发reflow影响属性。使用了文档碎片对象fragment来暂存需求插入页面中DOM元素。
4 在”__defineGetter__” “outerHTML”
中使用要素attributes属性来遍历给元素指定的特性。结合innerHTML重回了含蓄原属本身在内的html字符串。
测试代码:

生命周期和回调

在那些 API 的功底上,Web Components
标准提供了一多元决定自定义元素的办法。大家来挨家挨户看下:

一个自定义元素会经历以下那个生命周期:

  • 挂号前创办
  • 挂号自定义元素定义
  • 在登记后创制元素实例
  • 要素插入到 document 中
  • 元素从 document 中移除
  • 要素的品质变化时

其一是很重大的始末,开发者可以在登记新的自定义元素时指定相应的生命周期回调来为自定义元素添加种种自定义的行事,那个生命周期回调包罗了:

  • createdCallback
    自定义元素注册后,在实例化之后会调用,平时多用来做元素的伊始化,如插入子元素,绑定事件等。
  • attachedCallback
    要素插入到 document 时接触。
  • detachedCallback
    要素从 document 中移除时接触,可能会用来做类似 destroy 之类的事务。
  • attributeChangedCallback
    要素属性变化时接触,可以用于从外到内的通讯。外部通过改动元素的质量来让里面获得相关的数码同时实施相应的操作。

本条回调在不相同情形下有对应分裂的参数:

  • 安装属性时,参数列表是:属性名称,null,值,命名空间
  • 修改属性时,参数列表是:属性名称,旧值,新值,命名空间
  • 除去属性时,参数列表是:属性名称,旧值,null,命名空间

好了,就上边明白到的基础上,即使大家要创设一个自定义的 button-hello
按钮,点击时会 alert('hello world'),代码如下:

JavaScript

document.registerElement(‘button-hello’, { prototype:
Object.create(HTMLButtonElement.prototype, { createdCallback: { value:
function createdCallback() { this.innerHTML = ‘<button>hello
world</button>’ this.addEventListener(‘click’, () => {
alert(‘hello world’) }) } } }) })

1
2
3
4
5
6
7
8
9
10
11
12
document.registerElement(‘button-hello’, {
  prototype: Object.create(HTMLButtonElement.prototype, {
    createdCallback: {
      value: function createdCallback() {
        this.innerHTML = ‘<button>hello world</button>’
        this.addEventListener(‘click’, () => {
          alert(‘hello world’)
        })
      }
    }
  })
})

要注意上述代码执行之后才能应用 <button-hello></button-hello>

HTML导入文本中的window和document对象

眼前我提过在导入HTML文件的时候里面的脚本是会被实施的,但那并不意味HTML导入文本中的标签也会被浏览器渲染。你须求写一些JavaScript代码来帮衬。

当在HTML导入文本中应用JavaScript时,有一些要预防的是,HTML导入文本中的document对象实际指的是HTML主文件中的document对象。在此从前边的代码为例,index.html和
 component.html
的document都是指index.html的document对象。怎么才能使用HTML导入文本中的document
呢?借助link中的import 属性。

index.html

XHTML

var link = document.querySelector(‘link[rel=”import”]’);
link.addEventListener(‘load’, function(e) { var importedDoc =
link.import; // importedDoc points to the document under component.html
});

1
2
3
4
5
var link = document.querySelector(‘link[rel="import"]’);
link.addEventListener(‘load’, function(e) {
  var importedDoc = link.import;
  // importedDoc points to the document under component.html
});

为了博取component.html中的document 对象,要选用document.currentScript.ownerDocument.

component.html

XHTML

var mainDoc = document.currentScript.ownerDocument; // mainDoc points to
the document under component.html

1
2
var mainDoc = document.currentScript.ownerDocument;
// mainDoc points to the document under component.html

假使您在用webcomponents.js,那么就用document._currentScript来顶替document.currentScript。下划线用于填充currentScript属性,因为并不是有所的浏览器都协助这一个特性。

component.html

XHTML

var mainDoc = document._currentScript.ownerDocument; // mainDoc points
to the document under component.html

1
2
var mainDoc = document._currentScript.ownerDocument;
// mainDoc points to the document under component.html

由此在剧本起初添加上边的代码,你就足以轻松地拜会component.html中的document对象,而不用管浏览器是否永葆HTML导入。

XHTML

document._currentScript = document._currentScript ||
document.currentScript;

1
document._currentScript = document._currentScript || document.currentScript;

复制代码 代码如下:

扩充原有元素

实在,如若大家需求一个按钮,完全不需求重新自定义一个元素,Web Components
标准提供了一种伸张现有标签的办法,把下边的代码调整一下:

JavaScript

document.registerElement(‘button-hello’, { prototype:
Object.create(HTMLButtonElement.prototype, { createdCallback: { value:
function createdCallback() { this.addEventListener(‘click’, () => {
alert(‘hello world’) }) } } }), extends: ‘button’ })

1
2
3
4
5
6
7
8
9
10
11
12
document.registerElement(‘button-hello’, {
  prototype: Object.create(HTMLButtonElement.prototype, {
    createdCallback: {
      value: function createdCallback() {
        this.addEventListener(‘click’, () => {
          alert(‘hello world’)
        })
      }
    }
  }),
  extends: ‘button’
})

接下来在 HTML 中要如此使用:

XHTML

<button is=”button-hello”>hello world</button>

1
<button is="button-hello">hello world</button>

使用 is
属性来声称一个扩张的品种,看起来也蛮酷的。生命周期和自定义元素标签的保持一致。

当我们须要多个标签组合成新的元素时,大家可以运用自定义的因素标签,不过一旦只是急需在原始的
HTML 标签上拓展增添的话,使用 is 的那种元素增加的法子就好。

原有的 createElementcreateElementNS,在 Web Components
标准中也伸张成为协理元素增加,例如要创制一个 button-hello

JavaScript

const hello = document.createElement(‘button’, ‘button-hello’)

1
const hello = document.createElement(‘button’, ‘button-hello’)

标准文档中还有不少细节上的情节,例如接口的参数表达和要求,回调队列的兑现必要等,那一个愈来愈多是对于落成那么些标准的浏览器开发者的渴求,这里不做详细描述了,内容很多,有趣味的机动查阅:Cutsom
Elements
2016.02.26。

质量方面的设想

选取HTML
导入的一个益处是可以将资源公司起来,不过也表示在加载这个资源的时候,由于应用了有的额外的HTML文件而让尾部变得过大。有几点是急需考虑的:

<!DOCTYPE html>
<html>
<head>
<meta charset=”utf-8″ />
<title>outerHTML</title>
</head>
<body>
<div id=”content” class=”test”>
<p>This is <strong>paragraph</strong> with a list
following it</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
<script>
if(typeof HTMLElement !== “undefined” && !(“outerHTML” in
HTMLElement.prototype)) {
console.log(“defined outerHTML”);
HTMLElement.prototype.__defineSetter__(“outerHTML”,function(str){
var fragment = document.createDocumentFragment();
var div = document.createElement(“div”);
div.innerHTML = str;
for(var i=0, n = div.childNodes.length; i<n; i++){
fragment.appendChild(div.childNodes[i]);
}
this.parentNode.replaceChild(fragment, this);
});
//
HTMLElement.prototype.__defineGetter__(“outerHTML”,function(){
var tag = this.tagName;
var attributes = this.attributes;
var attr = [];
//for(var name in attributes){//遍历原型链上成员
for(var i=0,n = attributes.length; i<n; i++){//n指定的性质个数
if(attributes[i].specified){
attr.push(attributes[i].name + ‘=”‘ + attributes[i].value + ‘”‘);
}
}
return ((!!this.innerHTML) ?
‘<‘ + tag + ‘ ‘ + attr.join(‘
‘)+’>’+this.innerHTML+'</’+tag+’>’ :
‘<‘ + tag + ‘ ‘ +attr.join(‘ ‘)+’/>’);
});
}
var content = document.getElementById(“content”);
alert(content.outerHTML)
</script>
</body>
</html>

和新型版的区分

面前我提到说文档的更新变更很快,为止至自己写那么些稿子的时候,最新的文档是其一:Custom
Elements 2016.07.21。

细节不做描述了,讲讲自己看齐的最大变迁,就是向 ES6 靠拢。大概有下面三点:

  • 从原来的壮大 prototype 来定义元素调整为提议选用 class extends 的章程
  • 登记自定义元素接口调整,越发方便使用,传入 type 和 class 即可
  • 生命周期回调调整,createdCallback 直接用 class 的 constructor

前多少个点,我们直接看下代码,原本的代码根据新的规范,应该调整为:

JavaScript

class ButtonHelloElement extends HTMLButtonElement { constructor() {
super() this.addEventListener(‘click’, () => { alert(‘hello world’)
}) } } customElements.define(‘button-hello’, ButtonHelloElement, {
extends: ‘button’ })

1
2
3
4
5
6
7
8
9
10
11
class ButtonHelloElement extends HTMLButtonElement {
  constructor() {
    super()
 
    this.addEventListener(‘click’, () => {
      alert(‘hello world’)
    })
  }
}
 
customElements.define(‘button-hello’, ButtonHelloElement, { extends: ‘button’ })

从代码上看会感觉到尤其OO,编写上也比原来要出示方便一些,原本的生命周期回调是调动为新的:

  • constructor in class 效用相当于原来的 createdCallback
  • connectedCallback 效率约等于 attachedCallback
  • disconnectedCallback 功效相当于 detachedCallback
  • adoptedCallback 使用 document.adoptNode(node) 时触发
  • attributeChangedCallback 和原来保持一致

connect 事件和插入元素到 document 有微微区分,紧要就是插入元素到
document 时,元素状态会变成 connected,那时会触发
connectedCallback,disconnect 亦是如此。

分析器重

若果HTML主文件要信赖多个导入文本,而且导入文本中带有相同的库,那时会怎么样呢?例如,你要从导入文本中加载jQuery,假若每个导入文本都含有加载jQuery的script标签,那么jQuery就会被加载两回,并且也会被执行四次。

index.html

XHTML

<link rel=”import” href=”component1.html”> <link rel=”import”
href=”component2.html”>

1
2
<link rel="import" href="component1.html">
<link rel="import" href="component2.html">

component1.html

XHTML

<script src=”js/jquery.js”></script>

1
<script src="js/jquery.js"></script>

component2.html

XHTML

<script src=”js/jquery.js”></script>

1
<script src="js/jquery.js"></script>

HTML导入自动帮你解决了这一个标题。

与加载一次script标签的做法各异,HTML
导入对已经加载过的HTML文件不再举行加载和实践。从前边的代码为例,通过将加载jQuery的script标签打包成一个HTML导入文本,那样jQuery就只被加载和履行一回了。

但那还有一个题材:大家扩展了一个要加载的文件。怎么处理多少膨胀的文书呢?幸运的是,我们有一个叫vulcanize的工具来解决那几个题材。

比方要取得 <p id=”outerID”>sdfdsdfsd</p> 的 P的outerHTML
代码:

HTML Imports

合并互联网请求

Vulcanize 能将五个HTML文件合并成一个文书,从而裁减了互联网连接数。你可以信赖npm安装它,并且用命令行来行使它。你可能也在用 grunt和gulp 托管有些职责,那样的话你可以把vulcanize作为创设进程的一片段。

为精通析依赖以及联合index.html中的导入文本,使用如下命令:

JavaScript

$ vulcanize -o vulcanized.html index.html

1
$ vulcanize -o vulcanized.html index.html

经过实践那些命令,index.html中的信赖会被分析,并且会生出一个联合的HTML文件,称作 vulcanized.html。学习更多关于vulcanize的学问,请看这儿。

注意:http2的服务器推送作用被考虑用于以后消除文件的连接与统一。

复制代码 代码如下:

概述

HTML Imports 是一种在 HTMLs 中援引以及复用其他的 HTML 文档的法子。那些Import 很漂亮,可以不难了解为大家广大的模版中的include 之类的效应。

大家最广大的引入一个 css 文件的不二法门是:

XHTML

<link rel=”stylesheet” href=”/css/master.css”>

1
<link rel="stylesheet" href="/css/master.css">

Web Components 现在提供多了一个以此:

XHTML

<link rel=”import” href=”/components/header.html”>

1
<link rel="import" href="/components/header.html">

把Template、Shadow DOM、自定义元素跟HTML导入结合起来

让我们对那些作品种类的代码应用HTML导入。你前边恐怕没有看过那些小说,我先解释一下:Template可以让您用表明的艺术定义你的自定义元素的内容。Shadow
DOM可以让一个要素的style、ID、class只效劳到其自身。自定义元素得以让您自定义HTML标签。通过把那几个跟HTML导入结合起来,你自定义的web
组件会变得模块化,具有复用性。任哪个人添加一个Link标签就足以接纳它。

x-component.html

XHTML

<template id=”template”> <style> … </style> <div
id=”container”> <img
src=”; <content
select=”h1″></content> </div> </template>
<script> // This element will be registered to index.html //
Because `document` here means the one in index.html var XComponent =
document.registerElement(‘x-component’, { prototype:
Object.create(HTMLElement.prototype, { createdCallback: { value:
function() { var root = this.createShadowRoot(); var template =
document.querySelector(‘#template’); var clone =
document.importNode(template.content, true); root.appendChild(clone); }
} }) }); </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template id="template">
  <style>
    …
  </style>
  <div id="container">
    <img src="http://webcomponents.org/img/logo.svg">
    <content select="h1"></content>
  </div>
</template>
<script>
  // This element will be registered to index.html
  // Because `document` here means the one in index.html
  var XComponent = document.registerElement(‘x-component’, {
    prototype: Object.create(HTMLElement.prototype, {
      createdCallback: {
        value: function() {
          var root = this.createShadowRoot();
          var template = document.querySelector(‘#template’);
          var clone = document.importNode(template.content, true);
          root.appendChild(clone);
        }
      }
    })
  });
</script>

index.html

XHTML

… <link rel=”import” href=”x-component.html”> </head>
<body> <x-component> <h1>This is Custom
Element</h1> </x-component> …

1
2
3
4
5
6
7
8
  <link rel="import" href="x-component.html">
</head>
<body>
  <x-component>
    <h1>This is Custom Element</h1>
  </x-component>
  …

只顾,因为x-component.html 中的document 对象跟index.html的相同,你没要求再写一些讨厌的代码,它会自行为你注册。

var _p = document.getElementById(‘outerID’);
_P = _P.cloneNode();
var _DIV = document.createElement();
_DIV.appendChild(_P);
alert(_DIV.innerHTML); 就是P的outerHTML;

HTMLLinkElement

原本的 link 标签在添加了 HTML Import 之后,多了一个只读的 import
属性,当出现下面三种处境时,这些特性为 null

  • link 不是用来 import 一个 HTML 的。
  • link 元素不在 document 中。

不然,这些特性会回到一个意味着引入的 HTML 文件的文档对象,类似于
document。比如说,在上头的代码基础上,可以这么做:

JavaScript

const link = document.querySelector(‘link[rel=import]’) const header =
link.import; const pulse = header.querySelector(‘div.logo’);

1
2
3
4
const link = document.querySelector(‘link[rel=import]’)
const header = link.import;
 
const pulse = header.querySelector(‘div.logo’);

支撑的浏览器

Chrome 和
Opera提供对HTML导入的帮忙,Firefox要在二〇一四年17月后才支撑(Mozilla表示Firefox不安排在近日提供对HTML导入的辅助,声称须要首先精通ES6的模块是如何贯彻的)。

您可以去chromestatus.com或caniuse.com询问浏览器是还是不是协理HTML导入。想要在其余浏览器上应用HTML导入,可以用webcomponents.js(原名platform.js)。

firefox没有outerHTML用以下情势解决

阻塞式

大家要明了的是,默许的 link 加载是阻塞式的,除非你给她添加一个 async
标识。

阻塞式从某种程度上讲是有须求的,当您 improt
的是一个一体化的自定义组件并且需要在主 HTML
中用竹签直接行使时,非阻塞的就会现出谬误了,因为标签还平昔不被登记。

连带资源

HTML导入就介绍这么多了。如果您想学越来越多关于HTML导入的学识,请前往:

  • HTML Imports: #include for the web –
    HTML5Rocks
  • HTML Imports
    spec

    赞 1 收藏
    评论

复制代码 代码如下:

document

有好几值得注意的是,在 import 的 HTML 中,大家编辑的 script 里边的
document 是指向 import 这个 HTML 的主 HTML 的 document。

若果大家要拿走 import 的 HTML 的 document 的话,得如此来:

JavaScript

const d = document.currentScript.ownerDocument

1
const d = document.currentScript.ownerDocument

那般设计是因为 import 进来的 HTML 要求用到主 HTML 的
document。例如大家上边提到的 registerElement

在一个被 import 的 HTML 文件中行使下面七个方法会抛出一个
InvalidStateError
异常:

  • document.open()
  • document.write()
  • document.close()

对此 HTML
Import,标准文档中还有很大一些内容是关于多个依靠加载的处理算法的,在此处就不详述了,有时机的话找时间再开篇谈,这几个情节是索要浏览器去落到实处的。

至于作者:XfLoops

亚洲必赢官网 9

新浪腾讯网:@XfLoops
个人主页 ·
我的篇章 ·
10

亚洲必赢官网 10

/**
* 包容firefox的 outerHTML
使用以下代码后,firefox能够行使element.outerHTML
**/
if(window.HTMLElement) {
HTMLElement.prototype.__defineSetter__(“outerHTML”,function(sHTML){
var r=this.ownerDocument.createRange();
r.setStartBefore(this);
var df=r.createContextualFragment(sHTML);
this.parentNode.replaceChild(df,this);
return sHTML;
});
HTMLElement.prototype.__defineGetter__(“outerHTML”,function(){
var attr;
var attrs=this.attributes;
var str=”<“+this.tagName.toLowerCase();
for(var i=0;i<attrs.length;i++){
attr=attrs[i];
if(attr.specified)
str+=” “+attr.name+’=”‘+attr.value+'”‘;
}
if(!this.canHaveChildren)
return str+”>”;
return
str+”>”+this.innerHTML+”</”+this.tagName.toLowerCase()+”>”;
});
HTMLElement.prototype.__defineGetter__(“canHaveChildren”,function(){
switch(this.tagName.toLowerCase()){
case “area”:
case “base”:
case “basefont”:
case “col”:
case “frame”:
case “hr”:
case “img”:
case “br”:
case “input”:
case “isindex”:
case “link”:
case “meta”:
case “param”:
return false;
}
return true;
});
}

HTML Templates

测试有效.
关于insertAdjacentHTML包容的解新决办法

概述

以此事物很粗略,用过 handlebars 的人都知道有诸如此类一个事物:

XHTML

<script id=”template” type=”text/x-handlebars-template”> …
</script>

1
2
3
<script id="template" type="text/x-handlebars-template">
  …
</script>

其余模板引擎也有相近的东西,那么 HTML Templates
便是把那几个东西官方口径,提供了一个 template
标签来存放未来必要可是暂时不渲染的 HTML 代码。

从此可以这么写了:

XHTML

<template id=”template”> … </template>

1
2
3
<template id="template">
  …
</template>

复制代码 代码如下:

接口和使用

template 元素有一个只读的属性 content,用于重返这几个 template
里边的始末,重临的结果是一个 DocumentFragment

具体是如何行使的,直接参考官方给出的事例:

XHTML

<!doctype html> <html lang=”en”> <head>
<title>Homework</title> <body> <template
id=”template”><p>Smile!</p></template>
<script> let num = 3; const fragment =
document.getElementById(‘template’).content.cloneNode(true); while
(num– > 1) {
fragment.firstChild.before(fragment.firstChild.cloneNode(true));
fragment.firstChild.textContent += fragment.lastChild.textContent; }
document.body.appendChild(fragment); </script> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!doctype html>
<html lang="en">
  <head>
    <title>Homework</title>
  <body>
    <template id="template"><p>Smile!</p></template>
    <script>
      let num = 3;
      const fragment = document.getElementById(‘template’).content.cloneNode(true);
      while (num– > 1) {
        fragment.firstChild.before(fragment.firstChild.cloneNode(true));
        fragment.firstChild.textContent += fragment.lastChild.textContent;
      }
      document.body.appendChild(fragment);
    </script>
</html>

使用 DocumentFragment 的 clone 方法以 template
里的代码为底蕴创制一个因素节点,然后你便得以操作这么些因素节点,最终在急需的时候插入到
document 中一定岗位便可以了。

Template 相关的事物不多,而且它现在早就是纳入生效的
专业文档
中了。

大家接下去看重视磅的 Shadow DOM。

//—在组件最后插入html代码
function InsertHtm(op,code,isStart){
if(Dvbbs_IsIE5)
op.insertAdjacentHTML(isStart ? “afterbegin” : “afterEnd”,code);
else{
var range=op.ownerDocument.createRange();
range.setStartBefore(op);
var fragment = range.createContextualFragment(code);
if(isStart)
op.insertBefore(fragment,op.firstChild);
else
op.appendChild(fragment);
}
}

Shadow DOM

有关inner/outerHTML在NC6中的参考
DOM level 1 has no methods to allow for insertion of unparsed HTML into
the document tree (as IE allows with insertAdjacentHTML or assignment to
inner/outerHTML).NN6 (currently in beta as NN6PR3) know supports the
.innerHTMLproperty of HTMLElements so that you can read or write the
innerHTML of a page element like in IE4+.NN6 also provides a DOM level 2
compliant Range object to which a createContextualFragment(‘html source
string’)was added to spare DOM scripters the task of parsing html and
creating DOM elements.You create a Range with var range =
document.createRange();Then you should set its start point to the
element where you want to insert the html for instance var someElement =
document.getElementById(‘elementID’);
range.setStartAfter(someElement);Then you create a document fragment
from the html source to insert for example var docFrag =
range.createContextualFragment(‘<P>Kibology for
all.</P>’);and insert it with DOM methods
someElement.appendChild(docFrag);The Netscape JavaScript 1.5 version
even provides so called setters for properties which together with the
ability to prototype the DOM elements allows to emulate setting of
outerHMTL for NN6:<SCRIPT LANGUAGE=”JavaScript1.5″>if
(navigator.appName == ‘Netscape’) { HTMLElement.prototype.outerHTML
setter = function (html) { this.outerHTMLInput = html; var range =
this.ownerDocument.createRange(); range.setStartBefore(this); var
docFrag = range.createContextualFragment(html);
this.parentNode.replaceChild(docFrag, this); }}</SCRIPT> If you
insert that script block you can then write cross browser code assigning
to .innerHTML .outerHTMLfor instance document.body.innerHTML =
‘<P>Scriptology for all</P>’;which works with both IE4/5 and
NN6.The following provides getter functions for .outerHTMLto allow to
read those properties in NN6 in a IE4/5 compatible way. Note that while
the scheme of traversing the document tree should point you in the right
direction the code example might not satisfy your needs as there are
subtle difficulties when trying to reproduce the html source from the
document tree. See for yourself whether you like the result and improve
it as needed to cover other exceptions than those handled (for the empty
elements and the textarea
element).<HTML><HEAD><STYLE></STYLE><SCRIPT
LANGUAGE=”JavaScript1.5″>var emptyElements = { HR: true, BR: true,
IMG: true, INPUT: true};var specialElements = { TEXTAREA:
true};HTMLElement.prototype.outerHTML getter = function () { return
getOuterHTML (this);}function getOuterHTML (node) { var html = ”;
switch (node.nodeType) { case Node.ELEMENT_NODE: html += ‘<‘; html
+= node.nodeName; if (!specialElements[node.nodeName]) { for (var a =
0; a < node.attributes.length; a++) html += ‘ ‘ +
node.attributes[a].nodeName.toUpperCase() + ‘=”‘ +
node.attributes[a].nodeValue + ‘”‘; html += ‘>’; if
(!emptyElements[node.nodeName]) { html += node.innerHTML; html +=
‘<\/’ + node.nodeName + ‘>’; } } else switch (node.nodeName) {
case ‘TEXTAREA’: for (var a = 0; a < node.attributes.length; a++) if
(node.attributes[a].nodeName.toLowerCase() != ‘value’) html += ‘ ‘ +
node.attributes[a].nodeName.toUpperCase() + ‘=”‘ +
node.attributes[a].nodeValue + ‘”‘; else var content =
node.attributes[a].nodeValue; html += ‘>’; html += content; html +=
‘<\/’ + node.nodeName + ‘>’; break; } break; case
Node.TEXT_NODE: html += node.nodeValue; break; case Node.COMMENT_NODE:
html += ‘<!’ + ‘–‘ + node.nodeValue + ‘–‘ + ‘>’; break; } return
html;}</SCRIPT></HEAD><BODY><A HREF=”javascript:
alert(document.documentElement.outerHTML); void 0″>show
document.documentElement.outerHTML</A>|<A HREF=”javascript:
alert(document.body.outerHTML); void 0″>show
document.body.outerHTML</A>|<A HREF=”javascript:
alert(document.documentElement.innerHTML); void 0″>show
document.documentElement.innerHTML</A>|<A HREF=”javascript:
alert(document.body.innerHTML); void 0″>show
document.body.innerHTML</A><FORM
NAME=”formName”><TEXTAREA NAME=”aTextArea” ROWS=”5″
COLS=”20″>JavaScript.FAQTs.comKibology for
all.</TEXTAREA></FORM><DIV><P>JavaScript.FAQTs.com</P><BLOCKQUOTE>Kibology
for all.<BR>All for
Kibology.</BLOCKQUOTE></DIV></BODY></HTML>Note
that the getter/setter feature is experimental and its syntax is subject
to change.
HTMLElement.prototype.innerHTML setter = function (str) { var r =
this.ownerDocument.createRange(); r.selectNodeContents(this);
r.deleteContents(); var df = r.createContextualFragment(str);
this.appendChild(df); return str;}HTMLElement.prototype.outerHTML setter
= function (str) { var r = this.ownerDocument.createRange();
r.setStartBefore(this); var df = r.createContextualFragment(str);
this.parentNode.replaceChild(df, this); return str;}
HTMLElement.prototype.innerHTML getter = function () { return
getInnerHTML(this);}
function getInnerHTML(node) { var str = “”; for (var i=0;
i<node.childNodes.length; i++) str +=
getOuterHTML(node.childNodes.item(i)); return str;}
HTMLElement.prototype.outerHTML getter = function () { return
getOuterHTML(this)}
function getOuterHTML(node) { var str = “”; switch (node.nodeType) {
case 1: // ELEMENT_NODE str += “<” + node.nodeName; for (var i=0;
i<node.attributes.length; i++) { if
(node.attributes.item(i).nodeValue != null) { str += ” ” str +=
node.attributes.item(i).nodeName; str += “=\””; str +=
node.attributes.item(i).nodeValue; str += “\””; } }
if (node.childNodes.length == 0 && leafElems[node.nodeName]) str +=
“>”; else { str += “>”; str += getInnerHTML(node); str += “<” +
node.nodeName + “>” } break; case 3: //TEXT_NODE str +=
node.nodeValue; break; case 4: // CDATA_SECTION_NODE str +=
“<![CDATA[” + node.nodeValue + “]]>”; break; case 5: //
ENTITY_REFERENCE_NODE str += “&” + node.nodeName + “;” break;
case 8: // COMMENT_NODE str += “<!–” + node.nodeValue + “–>”
break; }
return str;}
var _leafElems = [“IMG”, “HR”, “BR”, “INPUT”];var leafElems = {};for
(var i=0; i<_leafElems.length; i++) leafElems[_leafElems[i]] =
true;
下一场大家能够封成JS引用
if (/Mozilla\/5\.0/.test(navigator.userAgent))
document.write(‘<script type=”text/javascript”
src=”mozInnerHTML.js”></sc’ + ‘ript>’);

概述

Shadow DOM
好像提议好久了,最本质的须求是索要一个隔离组件代码成效域的东西,例如我组件代码的
CSS 不可能影响其余零件之类的,而 iframe 又太重并且可能有各类意料之外难题。

能够那样说,Shadow DOM
目的在于提供一种更好地公司页面元素的方法,来为逐步复杂的页面使用提供强劲支撑,避免代码间的互相影响。

看下在 chrome 它会是怎么的:

亚洲必赢官网 11

咱俩得以因而 createShadowRoot() 来给一个元素节点创设 Shadow
Root,那几个因素类型必须是上边列表的其中一个,否则会抛出 NotSupportedError
非凡。

  • 自定义的因素
  • article
  • aside
  • blockquote
  • body
  • div
  • header, footer
  • h1, h2, h3, h4, h5, h6
  • nav
  • p
  • section
  • span

createShadowRoot() 是现在 chrome 已毕的
API,来自文档:https://www.w3.org/TR/2014/WD…。最新的文档
API 已经调整为 attachShadow()

归来的 Shadow Root 对象从 DocumentFragment
继承而来,所以可以动用有关的一些措施,例如shadowRoot.getElementById('id')
来获取 Shadow DOM 里边的因素。

简单易行的施用如下:

JavaScript

const div = document.getElementById(‘id’) const shadowRoot =
div.createShadowRoot() const span = document.createElement(‘span’)
span.textContent = ‘hello world’ shadowRoot.appendChild(span)

1
2
3
4
5
6
const div = document.getElementById(‘id’)
const shadowRoot = div.createShadowRoot()
const span = document.createElement(‘span’)
 
span.textContent = ‘hello world’
shadowRoot.appendChild(span)

在那里,我把那个 div 成为是以此 Shadow DOM 的
宿主元素,上边的始末会持续使用这一个叫做。

Shadow DOM 本身就为了代码隔离而生,所以在 document 上采纳 query
时,是迫不得已获取到 Shadow DOM 里边的元素的,须要在 Shadow Root 上做 query
才行。

在那里附上一个文档,里边有详尽的关于新的正式和明日 blink 引擎达成的
Shadow DOM 的界别,官方上称为 v0 和 v1:Shadow DOM v1 in
Blink。

复制代码 代码如下:

API

Shadow Root 除了从 DocumentFragment
继承而来的特性和章程外,还多了别的五个属性:

  • host 只读属性,用来收获这几个 Shadow Root 所属的要素
  • innerHTML 用来得到或者设置里边的 HTML 字符串,和我们常用的
    element.innerHTML 是同等的

除此以外,在新式的正规化文档中,元素除了下面提到的 attachShadow
方法之外,还多了七个特性:

  • assignedSlot 只读,这几个元素若是被分配到了某个 Shadow DOM 里边的
    slot,那么会重临那么些相应的 slot 元素
  • slot 元素的 slot 属性,用来指定 slot 的名目
  • shadowRoot 只读,元素下边对应的 Shadow Root 对象

slot 是何许?接着看下边的情节,看完下一节的结尾一有的就会清楚上述情节和
slot 相关的七个 API 有哪些效益。

<script language=”JavaScript” type=”Text/JavaScript”>
<!–
var emptyElements = { HR: true, BR: true, IMG: true, INPUT: true }; var
specialElements = { TEXTAREA: true };
HTMLElement.prototype.outerHTML getter = function() {
return getOuterHTML(this);
}
function getOuterHTML(node) {
var html = ”;
switch (node.nodeType) {
case Node.ELEMENT_NODE: html += ‘<‘; html += node.nodeName; if
(!specialElements[node.nodeName]) {
for (var a = 0; a < node.attributes.length; a++)
html += ‘ ‘ + node.attributes[a].nodeName.toUpperCase() + ‘=”‘ +
node.attributes[a].nodeValue + ‘”‘;
html += ‘>’;
if (!emptyElements[node.nodeName]) {
html += node.innerHTML;
html += ‘<\/’ + node.nodeName + ‘>’;
}
} else
switch (node.nodeName) {
case ‘TEXTAREA’: for (var a = 0; a < node.attributes.length; a++)
if (node.attributes[a].nodeName.toLowerCase() != ‘value’)
html
+= ‘ ‘ + node.attributes[a].nodeName.toUpperCase() + ‘=”‘ +
node.attributes[a].nodeValue

slot

slot
提供了在选择自定义标签的时候可以传递子模板给到里头使用的能力,可以简容易单看下
Vue 的一个例证。

俺们先来看下现在 chrome 可以跑的 v0 版本,这么些本子是提供了一个 content
标签,代表了一个占位符,并且有一个 select 属性用来指定使用什么子元素。

XHTML

<!– component input-toggle template –> <input
type=”checkbox”></input> <content
select=”.span”></content>

1
2
3
<!– component input-toggle template –>
<input type="checkbox"></input>
<content select=".span"></content>

自定义的因素里边的子元素代码是如此的:

XHTML

<input-toggle name=”hello”> <span>hello</span>
<span class=”span”>test</span> </input-toggle>

1
2
3
4
<input-toggle name="hello">
  <span>hello</span>
  <span class="span">test</span>
</input-toggle>

那么彰显的结果会和下部的代码是一模一样的:

XHTML

<input-toggle name=”hello”> <input
type=”checkbox”></input> <span
class=”span”>test</span> </input-toggle>

1
2
3
4
<input-toggle name="hello">
  <input type="checkbox"></input>
  <span class="span">test</span>
</input-toggle>

此处只是说呈现结实,实际上,input-toggle 里边应该是创建了一个 Shadow
DOM,然后 content 标签引用了目标的 span 内容,在 chrome 看是那般的:

亚洲必赢官网 12

接下来,是流行专业中的 slot 使用形式,直接上例子代码:

XHTML

<!– component input-toggle template –> <input
type=”checkbox”></input> <slot name=”text”></slot>

1
2
3
<!– component input-toggle template –>
<input type="checkbox"></input>
<slot name="text"></slot>

在自定义的因素标签是那般使用 slot 的:

XHTML

<input-toggle name=”hello”> <input
type=”checkbox”></input> <span class=”span”
slot=”text”>test</span> </input-toggle>

1
2
3
4
<input-toggle name="hello">
  <input type="checkbox"></input>
  <span class="span" slot="text">test</span>
</input-toggle>

通过 slot="text" 的品质来让要素内部的 slot
占位符可以引用到那些因素,八个元素采取那些特性也是可以的。那规范大家便具有了选用标签是从外部传
template 给到自定义元素的其中去采纳,而且富有指定放在那里的力量。

  • ‘”‘;
    else
    var content = node.attributes[a].nodeValue;
    html += ‘>’; html += content; html += ‘<\/’ + node.nodeName +
    ‘>’; break;
    } break;
    case Node.TEXT_NODE: html += node.nodeValue; break;
    case Node.COMMENT_NODE: html += ‘<!’ + ‘–‘ + node.nodeValue + ‘–‘
  • ‘>’; break;
    }
    return html;
    }
    //–>
    </script>

CSS 相关

因为有 Shadow DOM 的存在,所以在 CSS
上又添加了重重有关的东西,其中有的要么属于琢磨中的草案,命名之类的或许会有变动,上面提及的情节重点缘于文档:Shadow
DOM in CSS scoping
1,很多局地在 chrome
是早就落实的了,有趣味可以写 demo 试试。

因为 Shadow DOM
很大程度上是为着隔离样式功效域而诞生的,主文档中的样式规则不对 Shadow
DOM 里的子文档生效,子文档中的体制规则也不影响外部文档。

但不可防止的,在少数场景下,我们须要外部可以操纵 Shadow DOM
中样式,如提供一个零件给你,有时候你会期待得以自定义它里面的一些体裁,同时,Shadow
DOM
中的代码有时候可能须要可以决定其所属元素的体制,甚至,组件内部可以定义上面提到的经过
slot 传递进入的 HTML 的体裁。所以呢,是的,CSS
选拔器中添加了几个伪类,大家逐条来看下它们有哪些意义。

在读书下边描述的时候,请留心一下选拔器的代码是在哪些地点的,Shadow DOM
内部依旧外部。

:host 用于在 Shadow DOM 内部甄选到其宿主元素,当它不是在 Shadow DOM
中使用时,便匹配不到任意元素。

在 Shadow DOM 中的 * 拔取器是无力回天取舍到其宿主元素的。

:host( <selector> )
括号中是一个选用器,那些能够了然为是一个用以包容在主文档和 Shadow DOM
中使用的章程,当以此接纳器在 Shadow DOM
中时,会协作到括号中接纳器对应的宿主元素,要是或不是,则匹配括号中拔取器可以合营到的因素。

文档中提供了一个事例:

XHTML

<x-foo class=”foo”> <“shadow tree”> <div
class=”foo”>…</div> </> </x-foo>

1
2
3
4
5
<x-foo class="foo">
  <"shadow tree">
    <div class="foo">…</div>
  </>
</x-foo>

在这个 shadow tree 内部的体制代码中,会有诸如此类的结果:

  • :host 匹配 <x-foo> 元素
  • x-foo 匹配不到元素
  • .foo 只匹配到 <div> 元素
  • .foo:host 匹配不到元素
  • :host(.foo) 匹配 <x-foo> 元素

:host-context( <selector> )亚洲必赢官网 ,,用于在 Shadow DOM
中来检测宿主元素的父级元素,借使宿主元素或者其祖先元素可以被括号中的选取器匹配到的话,那么那几个伪类选拔器便匹配到那个Shadow DOM
的宿主元素。个人了解是用以在宿主元素外部因素满意一定的尺度时累加样式。

::shadow 这些伪类用于在 Shadow DOM 外部匹配其里面的要素,而 /deep/
那些标识也有雷同的功效,我们来看一个例子:

XHTML

<x-foo> <“shadow tree”> <div> <span
id=”not-top”>…</span> </div> <span
id=”top”>…</span> </> </x-foo>

1
2
3
4
5
6
7
8
<x-foo>
   <"shadow tree">
     <div>
       <span id="not-top">…</span>
     </div>
     <span id="top">…</span>
   </>
</x-foo>

对于上述这一段代码的 HTML 结构,在 Shadow DOM
外部的体制代码中,会是如此的:

  • x-foo::shadow > span 可以协作到 #top 元素
  • #top 匹配不到元素
  • x-foo /deep/ span 可以合作到 #not-top#top 元素

/deep/ 那几个标识的效益和大家的 >
选取器有点类似,只然则它是匹配其对应的 Shadow DOM
内部的,这几个标识可能还会转移,例如改成 >> 或者 >>>
之类的,个人感觉, >> 会更舒服。

末段一个,用于在 Shadow DOM 内部调整 slot
的体制,在自己查看的那个文档中,暂时是以 chrome 已毕的为准,使用
::content 伪类,不排除有立异为 ::slot
的可能性。大家看一个事例来明白一下,即使名称调整了也是大半的用法:

XHTML

<x-foo> <div id=”one” class=”foo”>…</div> <div
id=”two”>…</div> <div id=”three” class=”foo”> <div
id=”four”>…</div> </div> <“shadow tree”> <div
id=”five”>…</div> <div id=”six”>…</div>
<content select=”.foo”></content> </”shadow tree”>
</x-foo>

1
2
3
4
5
6
7
8
9
10
11
12
<x-foo>
  <div id="one" class="foo">…</div>
  <div id="two">…</div>
  <div id="three" class="foo">
    <div id="four">…</div>
  </div>
  <"shadow tree">
    <div id="five">…</div>
    <div id="six">…</div>
    <content select=".foo"></content>
  </"shadow tree">
</x-foo>

在 Shadow DOM 内部的样式代码中,::content div 可以匹配到
#one#three#four,留意一下 #two
为啥没被匹配到,因为它没有被 content
元素选中,即不会进展引用。假诺更换成 slot 的 name 引用的不二法门亦是同理。

层叠规则,按照这几个文档的说教,对于多个先行级别相同的 CSS 申明,没有带
!important 的,在 Shadow DOM 外部注脚的先行级高于在 Shadow DOM
内部的,而带有 !important
的,则相反。个人觉得,那是提需求外部自然的控制能力,同时让内部可以限制一定的影响范围。

继承方面相对简单,在 Shadow DOM 内部的顶尖元素样式从宿主元素继承而来。

迄今,Web Components
多个部分介绍停止了,其中有部分细节,浏览器完毕细节,还有使用上的一部分细节,是不曾提及的,因为详细笔录以来,还会有诸多事物,内容很多。当使用进程中有疑问时方可重复查看标准文档,有机遇的话会再完美那么些稿子。下一部分会把那多个内容结合起来,全体看下
Web Components 是怎么使用的。

Tree和render
tree的创设,从而进步页面质量。为此大家得以把页面中那个首屏渲染不可知的部…

Web Components

Web Components 总的来说是提供一整套宏观的包裹机制来把 Web
组件化那几个东西规范,每个框架完毕的零件都统一标准地展开输入输出,那样可以更好牵动组件的复用。结合上面各样部分的情节,大家结合一起来看下应该怎么利用那些专业来落到实处大家的零部件:

JavaScript

<!– components/header.html –> <template id=””>
<style> ::content li { display: inline-block; padding: 20px 10px;
} </style> <content select=”ul”></content>
</template> <script> (function() { const element =
Object.create(HTMLInputElement.prototype) const template =
document.currentScript.ownerDocument.querySelector(‘template’)
element.createdCallback = function() { const shadowRoot =
this.createShadowRoot() const clone =
document.importNode(template.content, true)
shadowRoot.appendChild(clone) this.addEventListener(‘click’,
function(event) { console.log(event.target.textContent) }) }
document.registerElement(‘test-header’, { prototype: element }) })()
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!– components/header.html –>
<template id="">
<style>
::content li {
  display: inline-block;
  padding: 20px 10px;
}
</style>
<content select="ul"></content>
</template>
<script>
(function() {
  const element = Object.create(HTMLInputElement.prototype)
  const template = document.currentScript.ownerDocument.querySelector(‘template’)
 
  element.createdCallback = function() {
    const shadowRoot = this.createShadowRoot()
    const clone = document.importNode(template.content, true)
    shadowRoot.appendChild(clone)
 
    this.addEventListener(‘click’, function(event) {
      console.log(event.target.textContent)
    })
  }
 
  document.registerElement(‘test-header’, { prototype: element })
})()
</script>

那是一个简练的机件的例证,用于定义一个
test-header,并且给传递进入的子元素 li
添加了部分零件内部的体裁,同时给组件绑定了一个点击事件,来打印点击目的的文件内容。

看下怎么着在一个 HTML 文件中引入并且选拔一个零件:

XHTML

<!– index.html –> <!DOCTYPE html> <html>
<head> <meta charset=”utf-8″> <title></title>
<link rel=”import” href=”components/header.html”> </head>
<body> <test-header> <ul> <li>Home</li>
<li>About</li> </ul> </test-header>
</body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!– index.html –>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
 
    <link rel="import" href="components/header.html">
  </head>
  <body>
    <test-header>
      <ul>
        <li>Home</li>
        <li>About</li>
      </ul>
    </test-header>
  </body>
</html>

一个 import<link> 把组件的 HTML
文件引用进来,那样会履行组件中的脚本,来注册一个 test-header
元素,那样子大家便可以在主文档中使用这些元素的价签。

上面的例子是可以在 chrome 正常运作的。

就此,按照上面简单的事例能够见到,各种部分的情节是有机构成在一起,Custom
Elements 提供了自定义元素和标签的能力,template 提供组件模板,import
提供了在 HTML 中合理引入组件的主意,而 Shadow DOM
则处理组件间代码隔离的难题。

只可以认可,Web Components
标准的提议解决了一部分难题,必须交由浏览器去处理的是 Shadow DOM,在一贯不
Shadow DOM
的浏览器上贯彻代码隔离的办法多多少少有瑕疵。个人自己认为组件化的逐一 API
不够简洁易用,依然有 getElementById
那一个的意味,可是交由逐一类库去简化也足以承受,而 import
成效上没问题,不过加载多个零件时质量难题仍旧值得说道,标准或者须求在这一个地方提供越多给浏览器的指点,例如是不是有可能提供一种单一请求加载三个零件
HTML 的章程等。

在现行的移动化趋势中,Web Components 不仅仅是 Web
端的题目,越多的开发者期望以 Web
的点子去落成移动使用,而多端复用的落实渐渐是以组件的款型铺开,例如
React Native 和
Weex。所以 Web Components
的正儿八经可能会影响到多端开发 Web 化的一个格局和进步。

说到底,再啰嗦一句,Web Components
个人认为照旧以后发展趋势,所以才有了那几个小说。

1 赞 4 收藏
评论

亚洲必赢官网 13

网站地图xml地图