Web Component
好累啊..腿好酸
看了一本书叫Web Component实战
准备
Web Component
有几个模块:模板元素
,Shadow DOM
,自定义元素
,HTML Import
模板元素
interface HTMLTemplateElement: HTMLELement {
readonly arttribute DocumentFragment content;
}
HTML Template元素的唯一一个元素content(类型为DocumentFragment)
检测是不是支持HTML Template
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Web Component: Template support</title>
</head>
<body>
<h1 id="message"></h1>
<script>
var isTemplateSupported = function() {
var template = document.createElement("template");
return 'content' in template;
}
var isSupported = isTemplateSupported(),
message = document.getElementById('message');
if(isSupported) {
message.innerHTML = "Supported";
} else {
message.innerHTML = "Not Supported";
}
</script>
</body>
</html>
模板是延迟加载的,要手动激活
方法有两种
cloneNode
<Node> <Target node>.cloneNode(<Boolean paramenter>)
参数:
- true 深克隆 目标节点的子节点也被clone
- false 浅克隆
返回值:
- <Node>
<div id="container"> </div>
<template id="aTemplate">
<h1>
Template is activated using cloneNode.
</h1>
</template>
<script>
var aTemplate = document.querySelector('#aTemplate'),
container = document.getElementById("container"),
templateContent = aTemplate.content,
activeContent = templateContent.cloneNode(true); //key
container.appendChild(activeContent);
</script>
importNode
<Node> document.importNode(<target Node>, <Boolean parameter>)
这个更像是函数式的写法
<div id="container"> </div>
<template id="aTemplate">
<h1>
Template is activated using cloneNode.
</h1>
</template>
<script>
var aTemplate = document.querySelector('#aTemplate'),
container = document.getElementById("container"),
templateContent = aTemplate.content,
activeContent = document.importNode(templateContent, true); //key
container.appendChild(activeContent);
</script>
HTML Import
可以像iframe一样,把外部的HTML嵌入页面
<link rel="import" href="fileName.html">
检测是否支持
var isImportSupport = function() {
var link = document.createElement('link');
return 'import' in link;
}
访问被引入的文档(通过import属性)
=> message.html
<h1>This is from another HTML file document.</h1>
=> index.html
<head>
<link rel="import" href="message.html">
</head>
<body>
<script>
(function() {
var externalDocument =
document.querySelector('link[rel="import"]').import;
var headerElement = externalDocument.querySelector('h1');
// document.body.appendChild(headerElement);
document.body.appendChild(headerElement.cloneNode(true));
})();
</script>
</body>
原文这里也是用了cloneNode
即为
document.body.appendChild(headerElement.cloneNode(true));
但试验了一下好像直接
document.body.appendChild(headerElement);
也是可以的
Shadow DOM
为了防止防止外部文档影响到Web Component,比如
- 文档样式表
- 文档的javascript代码
- 出现重复id
Shadow DOM 相当于把web Component封装起来,不受外部作用域影响
检测是否
var isShadowDOMSupported = function() {
return 'createShadowRoot' in document.body
}
Shadow tree
可以把一个Shadow tree 挂到某个DOM元素上,这个元素就作为宿主元素
<body>
<div id="aShadowHost"></div> <!-- 挂载点 -->
<template id="selectorTemplate"> <!-- 模板 可以clone,然后丢到shadow DOM 里-->
<style>
:host input{
background: lightyellow;
}
:host .labelClass{
color: blue;
}
</style>
<form>
... 省略若干html
</form>
</template>
<script>
(function() {
var aShadowHost = document.getElementById('aShadowHost');
var shadowRoot = aShadowHost.createShadowRoot(); //重点,敲黑板,相当于给aShadowHost挂载了一颗Shadow Tree
var TemplateContent = ... ; //此处省略把`selectorTemplate`cloneNode出来的过程
shadowRoot.appendChild(TemplateContent); //成功把模板挂到shadowRoot下面
// 其实可以挂很多个shadow tree
//现在的状况
/* div#aShadowHost
* /=> shadow-root
* /=> style
* /=> form
* /=> shadow-root 如果多createShadowRoot几次就能得到多个shadow DOM子树
* /=> ....
* /=> ....
*/
})();
</script>
</body>
自定义元素
检测
var isCustomElementSupportws = function() {
return 'registerElement' in document;
}
大概过程,具体参考MDN
var newObj = Object.create(HTMLElement.prototype);
Object.defineProperties(newObj, {
title: {
writeable:true
},
country: {
writeable:true,
value: 'India'
}
});
//定义生命周期方法(这个是不是就叫做钩子)
newObj.createCallback = function() {
//Do-something
}
//注册元素
var newTag = document.registerElement('Tag-name', {
prototype: newObj // 把我们前面辛辛苦苦create出来的obj注册成功了
});
使用
<Tag-name>
</Tag-name>
生命周期: created => attached => detached => attributeChanged
节点分布
两种插入点
content
对Shadow Host的子节点占位,反向映射Shadow Host的子节点
这个不太好理解,看他这个例子
shadow
shadow插入点是Shadow Tree的占位符,反向映射了Shadow Tree中的元素
哇 这个也不太好理解
然后发现了一个完整的Demo
抄完这个Demo就去写作业
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>Demo</title> <style> header-element:unresolved{ visibility:hidden; } header-element:unresolved:after{ content: 'Registering Element...'; color: red; visibility:visible; } </style> </head> <body> <template id="headerTemplate"> <style> :host{ text-transform:lowercase; } :host::shadow h1{ color:orange; } :host::content b{ color:blue; } </style> <h1> Hello <content></content> </h1> </template> <script> (function() { var objectPrototype = Object.create(HTMLElement.prototype); objectPrototype.createdCallback = function() { var shadow = this.createShadowRoot(), templateContent = document.querySelector('#headerTemplate').content; var templateNodes = document.importNode(templateContent, true); shadow.appendChild(templateNodes); // 成功挂载,要累死我了 }; window.setTimeout(function() { document.registerElement('header-element', { prototype: objectPrototype }) //延时注册 }, 3000); })(); </script> <header-element> <b>Web Component</b> </header-element> </body> </html>
心都碎了,说好的
:host::shadow h1{ color:orange; } :host::content b{ color:blue; }
这样子.应该是
Hello
橙色,web Component
蓝色啊
实际上运行结果是
firefox跑不出来
chrome上有加载效果,但加载出来都是橙色的,并且警告我::shadow pseudo-element is deprecated. See https://www.chromestatus.com/features/6750456638341120 for more details.
后来
书的后几章讲了一些具体的实现组件化web的库
有Polymer JS
, Mozilla Brick
, Bosonic
, ReactJS
喔,,以后学一下ReactJS
,稍微看了下,总感觉像是在拼接字符串
参考
https://github.com/w3c/webcomponents
http://w3c.github.io/webcomponents/spec/shadow/
https://www.toobug.net/article/what_is_shadow_dom.html
https://developer.mozilla.org/zh-cn/docs/web/web_components