Web Components
wenjuli(李文举)
Custom Elements
• How to build a custom element
• Naming rules
– 至少含有一个 ’-’
– 正确:x-component x-web-component
– 错误:web_component xelement XElement
var XComponent = document.registerElement('x-component');
<x-component></x-component>
Custom Elements
• Imperative usage
var XComponent = document.registerElement('x-component');
var dom = new XComponent();
document.body.appendChild(dom);
document.registerElement('x-component');
var dom = document.createElement('x-component');
document.body.appendChild(dom);
Custom Elements
• Adding features to a custom element
var proto = Object.create(HTMLElement.prototype);
proto.name = 'Custom Element';
proto.alert = function() {
alert('This is ' + this.name);
};
document.registerElement('x-component', {
prototype: proto
});
Custom Elements
• Type Extension Custom Element
– 自定义元素可以是从扩展原生HTML元素而来
– 定义类型扩展
• 创建基本原型对象,使用被扩展元素的原型,而不是使用HTMLElement
• 在document.registerElement()的第二个参数中添加 extends 键,值为被扩展元素的标签名
<div is="x-component"></div>
var XComponent = document.registerElement('x-component', {
extends: 'input',
prototype: Object.create(HTMLInputElement.prototype)
});
Custom Elements
• Lifecycle callbacks DEMO
– .createdCallback()
– .attachedCallback()
– .detachedCallback()
– .attributeChangedCallback()
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {
var div = document.createElement('div');
div.textContent = 'This is Custom Element';
this.appendChild(div);
};
var XComponent = document.registerElement('x-component', {
prototype: proto
});
Custom Elements
• 与Templates and Shadow DOM结合使用
– 方便处理和复用
– template: 声明式的定义自定义元素的内容
– shadow dom: 限定内容中ID, class, style的作用域
template
<div style="display:none;">
<div>
<h1>Web Components</h1>
<img src="http://webcomponents.org/img/logo.svg">
</div>
</div>
<script type="text/template">
<div>
<h1>Web Components</h1>
<img src="http://webcomponents.org/img/logo.svg">
</div>
</script>
template
• 惰性HTML标签
– 行内脚本不执行
– 资源(如<img>, <video>)不加载
• 定义template
<template id="template">
<style>
...
</style>
<div>
<h1>Web Components</h1>
<img src="http://webcomponents.org/img/logo.svg">
</div>
</template>
template
• 使用template内容
– http://jsbin.com/qaxiw/7/edit?html,css,output
<script>
var template = document.querySelector('#template');
var clone = document.importNode(template.content, true);
var host = document.querySelector('#host');
host.appendChild(clone);
</script>
<div id="host"></div>
template
• 无数据绑定功能
<template bind="{{items}}"></template>
<template repeat="{{item in items}}"></template>
<template if="{{item.active}}"></template>
shadow dom
• 解决 DOM树封装问题
• 表现与内容分离
<button>Hello, world!</button>
<script>
var host = document.querySelector(‘button’);
var root = host.createShadowRoot();
root.textContent = ‘你好,世界!’;
</script>
HTML Imports
• 问题
– 利用custom elements, template, shadow dom创建组件,如何加载html, css,
javaScript资源
– 如何删除重复依赖
• HTML Imports以一个合并的html文件加载这些资源
• 跨域导入
<link rel="import" href="component.html" >
HTML Imports
• 执行顺序
HTML Imports
• 导入文档中脚本在导入时会执行,但HTML标签并不会渲染,需要脚
本来处理
• 注意:导入文档中的document对象实际上指的是主文件的document对
象。
• 如何在主文档中引用导入文档中的document对象?
var link = document.querySelector('link[rel="import"]');
link.addEventListener('load', function(e) {
var importedDoc = link.import;
// importedDoc points to the document under
component.html
});
HTML Imports
• 如何在导入文档中获取其document对象?
• 性能
– 重复资源只加载一次
– 利用工具合并html片断
var mainDoc = document.currentScript.ownerDocument;
// mainDoc points to the document under component.html
<mc-header></mc-header>
<mc-aside></mc-aside>
项目文件组织应用
<link rel="import" href=”mc-frame.html">
<template id="template">
<!-- <link rel="stylesheet" href="mc-header.css"> link
文件会忽略-->
<style>
@import url(css/mc-header.css); <!-- 路径相对于主文
件 -->
</style>
<div class="header">
...
</div>
</template>
<script>
(function(doc){
var McHeader = document.registerElement('mc-header', {
prototype: Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
var root = this.createShadowRoot();
var template =
doc.querySelector('#template');
var clone =
document.importNode(template.content, true);
root.appendChild(clone);
}
}
})
});
})(document.currentScript.ownerDocument);
</script>
Thanks.

Web components

  • 1.
  • 3.
    Custom Elements • Howto build a custom element • Naming rules – 至少含有一个 ’-’ – 正确:x-component x-web-component – 错误:web_component xelement XElement var XComponent = document.registerElement('x-component'); <x-component></x-component>
  • 4.
    Custom Elements • Imperativeusage var XComponent = document.registerElement('x-component'); var dom = new XComponent(); document.body.appendChild(dom); document.registerElement('x-component'); var dom = document.createElement('x-component'); document.body.appendChild(dom);
  • 5.
    Custom Elements • Addingfeatures to a custom element var proto = Object.create(HTMLElement.prototype); proto.name = 'Custom Element'; proto.alert = function() { alert('This is ' + this.name); }; document.registerElement('x-component', { prototype: proto });
  • 6.
    Custom Elements • TypeExtension Custom Element – 自定义元素可以是从扩展原生HTML元素而来 – 定义类型扩展 • 创建基本原型对象,使用被扩展元素的原型,而不是使用HTMLElement • 在document.registerElement()的第二个参数中添加 extends 键,值为被扩展元素的标签名 <div is="x-component"></div> var XComponent = document.registerElement('x-component', { extends: 'input', prototype: Object.create(HTMLInputElement.prototype) });
  • 7.
    Custom Elements • Lifecyclecallbacks DEMO – .createdCallback() – .attachedCallback() – .detachedCallback() – .attributeChangedCallback() var proto = Object.create(HTMLElement.prototype); proto.createdCallback = function() { var div = document.createElement('div'); div.textContent = 'This is Custom Element'; this.appendChild(div); }; var XComponent = document.registerElement('x-component', { prototype: proto });
  • 8.
    Custom Elements • 与Templatesand Shadow DOM结合使用 – 方便处理和复用 – template: 声明式的定义自定义元素的内容 – shadow dom: 限定内容中ID, class, style的作用域
  • 9.
    template <div style="display:none;"> <div> <h1>Web Components</h1> <imgsrc="http://webcomponents.org/img/logo.svg"> </div> </div> <script type="text/template"> <div> <h1>Web Components</h1> <img src="http://webcomponents.org/img/logo.svg"> </div> </script>
  • 10.
    template • 惰性HTML标签 – 行内脚本不执行 –资源(如<img>, <video>)不加载 • 定义template <template id="template"> <style> ... </style> <div> <h1>Web Components</h1> <img src="http://webcomponents.org/img/logo.svg"> </div> </template>
  • 11.
    template • 使用template内容 – http://jsbin.com/qaxiw/7/edit?html,css,output <script> vartemplate = document.querySelector('#template'); var clone = document.importNode(template.content, true); var host = document.querySelector('#host'); host.appendChild(clone); </script> <div id="host"></div>
  • 12.
    template • 无数据绑定功能 <template bind="{{items}}"></template> <templaterepeat="{{item in items}}"></template> <template if="{{item.active}}"></template>
  • 13.
    shadow dom • 解决DOM树封装问题 • 表现与内容分离 <button>Hello, world!</button> <script> var host = document.querySelector(‘button’); var root = host.createShadowRoot(); root.textContent = ‘你好,世界!’; </script>
  • 14.
    HTML Imports • 问题 –利用custom elements, template, shadow dom创建组件,如何加载html, css, javaScript资源 – 如何删除重复依赖 • HTML Imports以一个合并的html文件加载这些资源 • 跨域导入 <link rel="import" href="component.html" >
  • 15.
  • 16.
    HTML Imports • 导入文档中脚本在导入时会执行,但HTML标签并不会渲染,需要脚 本来处理 •注意:导入文档中的document对象实际上指的是主文件的document对 象。 • 如何在主文档中引用导入文档中的document对象? var link = document.querySelector('link[rel="import"]'); link.addEventListener('load', function(e) { var importedDoc = link.import; // importedDoc points to the document under component.html });
  • 17.
    HTML Imports • 如何在导入文档中获取其document对象? •性能 – 重复资源只加载一次 – 利用工具合并html片断 var mainDoc = document.currentScript.ownerDocument; // mainDoc points to the document under component.html
  • 18.
  • 19.
    <template id="template"> <!-- <linkrel="stylesheet" href="mc-header.css"> link 文件会忽略--> <style> @import url(css/mc-header.css); <!-- 路径相对于主文 件 --> </style> <div class="header"> ... </div> </template>
  • 20.
    <script> (function(doc){ var McHeader =document.registerElement('mc-header', { prototype: Object.create(HTMLElement.prototype, { createdCallback: { value: function() { var root = this.createShadowRoot(); var template = doc.querySelector('#template'); var clone = document.importNode(template.content, true); root.appendChild(clone); } } }) }); })(document.currentScript.ownerDocument); </script>
  • 21.