w3ctech

说说 Web Components

Web Components 的现状

到目前为止,w3c定义的web components已经包含了

  • Templates, 提供一个包含html,css,js的代码片段,类似于一般模板引擎里的视图
  • Custom Elements, 提供一个自定义html元素的接口,支持对现有html元素的扩展
  • Imports, 提供对模板或者自定义元素这些资源的加载支持
  • Shadow DOM, 提供一个对外隐藏的web片段,而且支持独立的样式,不会破坏文档内的样式

web 组件的技术规范的制定就是为了保证前端组件的规范化,独立性,可重用性.先来说说Templates功能


Templates

Templates提供了类似于模板引擎里的视图功能,默认浏览器是不会渲染此标签的内容的,只有当你真正用的时候才会去render,下面给一个简单的使用Templates的例子


<template id="foo">
    <h2>Hello, world!</h2>
</template>

跟普通的html标签一样,定义一个id来标识这段代码,下面我们来使用这个模板


var template = document.querySelector('#foo');
document.querySelector('body').appendChild(template.content.cloneNode(true));

上面的代码就是往body里插入模板里的内容,这里要注意下,想要获取模板内的内容,得使用模板元素的content属性,内容的类型是documentFragment,一般在同时插入多个html内容的时候,用documentFragment是最有效率的, 这里还要注意下,假如直接把content的内容插入到目标元素内之后,模板的内容就会丢失,所以为了保证别的目标元素也想插入这个模板的话,可以使用NodecloneNode方法,这是所有html节点都有的方法,参数传递true的话会深度clone.

Custom Elements

自定义元素api接口提供了一个可以自定义html元素的方法,支持新增方法以及对现有的元素进行扩展

w3c提供了document.registerElement方法来创建一个新元素,先来一个简单的实例,然后再分析它的实现

var p = Object.create(HTMLElement.prototype);
p.hello = function () {
    this.appendChild("<h1>hello feenan</h1>");
}
var HelloFeenan = document.registerElement('hello-feenan', {prototype: p});

上面的代码创建一个名叫hello-feenan的元素,自定义的元素必须以-来连接,Object.create传递一个原型,将会创建继承这个原型的对象,然后对这个原型进行方法扩展,这里加了一个hello方法,定义完这个元素之后,怎么使用呢,其实它跟系统自带的元素一样,可以直接在html页里使用也可以动态的添加,这里使用document.createElement方法来添加,然后动态的添加body元素中

var el = document.createElement('hello-feenan');

document.querySelector('body').appendChild(el);

// 调用hello方法来添加子元素
document.querySelector('hello-feenan').hello();

上面的代码就是应用自定义元素的好例子,其实这里的hello方法的内容可以在自定义元素的初始化事件回调里执行,说到这里,就得提提customer element 的支持的事件了

  • createdCallback 自定义元素创建实例的时候触发
  • attachedCallback 当元素实例被添加到document文档流中时触发
  • detachedCallback 当从document文档流中删除自定义的元素实例时触发
  • attributeChangedCallback 当元素实例的属性修改的时候触发

这四个事件的回调函数必须定义在自定义元素的原型对象上面,比如上面的p,可以通过createdCallback事件来实现上面的hello方法的内容

p.createdCallback = function(){
    this.appendChild("<h1>hello feenan</h1>");
}

下面是一个完整的带自定义元素实现的例子

<html>
    <head>
        <title>customer elements</title>
        <meta charset="utf-8">
    </head>
    <body>
        <script>

            var helloFeenan = Object.create(HTMLElement.prototype);

            helloFeenan.hello = function(){
                this.appendChild("<h1>hello feenan</h1>");
            }

            // 当元素被创建的时候触发此回调函数
            helloFeenan.createdCallback = function(){
                this.appendChild("<h1>hello feenan</h1>");
            }
            document.registerElement('hello-feenan', { prototype: helloFeenan});

            var el = document.createElement('hello-feenan');

            document.querySelector('body').appendChild(el);


        </script>
    </body>
</html>

Imports

imports特性提供了以link方式来导入一段html文本的功能,相当于是template的进化版,方便做成模板文件

w3c规定linkrel属性传入import值,然后设置src为一个html文件,像下面这样的


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

那么在引入页面的dom里怎么获取导入的文件内容呢,w3crel=import的元素提供了import属性来获取文件内容,本质上是#document类型,可以像下面这样来获取内容


var link = $('link[rel=import]')[0];

var link_doc = link.import;

Shadow DOM

shadow dom根据字面意思就知道这是隐藏在dom节点里的元素,提供了对css,js,html的封装从而形成一个独立组件的功能,这是一个非常不错的特性,结合import可以实现一个可重用的Web组件功能替代现在的一些ui组件.

下面我们来看看怎么使用shadow dom

w3c提供了createShadowRoot方法,这属于element的方法,在元素上面调用这个方法将在它下面创建shadow dom子元素,可以像下面这样来使用


var shadowroot = $('.content')[0].createShadowRoot();
var elm = document.createElement('h1');
elm.textConent = 'hello feenan';
shadowroot.appendChild(elm);

一个完整的例子

目前chrome 36 已对template, import, shadow dom提供了完整的支持,所以下面提供一个结合三者的例子

  • link元素需要引入的import.html文件

<style>
    .content{
        margin: 20px;padding: 15px;
        width: 200px;height: 200px;
        border: 1px solid #ccc;border-radius: 5px;
        box-shadow: 0 0 10px red;
        overflow: auto;
    }
</style>
<div class="content">
    <h2>this is a test for ShadowRoot</h2>
</div>

上面的文件,chrome在用link引入之后,样式文件会放在link.importdocument里的head元素内,普通html元素会放入body中,知道了内容的位置,方便下面用的时候查找

  • index.html 运行例子的主html文件

<!doctype html>
<html>
<head>
    <title>web components</title>
    <meta charset='utf8'>
    <link rel="import" href="import.html">
    <style>
        .content{
            margin: 20px;padding: 15px;
            width: 300px;height: 400px;
            border: 1px solid #ccc;border-radius: 5px;
            box-shadow: 0 0 10px #009933 inset;
            overflow: auto;
        }
        .btn{
            width: 120px;line-height: 30px;
            font-size: 16px;
            text-align: center;
            padding: 10px 15px;
            border-radius: 5px;
            border: 1px solid #ccc;
            box-shadow: 0 0 5px #ddd;
        }
        .btn:focus{
            outline: none;
            box-shadow: 0 0 10px green;
        }
    </style>
</head>
<body>
    <div class="content">
    </div>
    <p class="tmpl"></p>
    <p>
        <button class="btn add">添加</button>
    </p>
    <template id="tmpl1">
        <h1>hello feenan!</h1>
    </template>
    <script src="/lib/jquery/dist/jquery.min.js"></script>
    <script>
        $('.add').click(function(){

            var link = $('link[rel=import]')[0];

            // 获取引入文件的模板内容,返回的其实是#document类型
            var link_doc = link.import;

            // 创建shadow dom 元素,本质是一个documetn片段元素
            var shadowroot = $('.content')[0].createShadowRoot();

            // 创建样式
            var style = function(){
                var css = document.createElement('style');
                // 通过styleSheets获取模板内的样式内容
                css.textContent = link_doc.styleSheets[0].rules[0].cssText;
                return css;
            }

            // 创建内容
            var body = function(){
                return $(link_doc.body.innerHTML)[0];
            }

            shadowroot.appendChild(style());
            shadowroot.appendChild(body());
            $('.content').append($(link_doc).find('body').html());

            // 使用template来获取模板文件
            $('.content').append($('#tmpl1')[0].content.cloneNode(true));

        });
    </script>
</body>
</html>
  • 以上的例子建议在chrome 36里运行

总结

非常高兴chrome36稳定版已对template,import,customer element,shadow dom提供了完整的支持,更多关于各个浏览器对web components支持请 点击这里

关于web components相关的网站,可以参考下面的地址,大部分都要翻墙浏览,因为基本上都是google维护的

webcomponents 官网

Polymer 框架, google出品的开发web组件的框架,兼容大部分浏览器

w3c web 组件规范

w3ctech微信

扫码关注w3ctech微信公众号

共收到3条回复

  • 很多人对这些都不熟,对于结构化开发相当有用。转了。

    回复此楼
  • 还真的不熟 = = 赞

    回复此楼
  • 赞!!!

    回复此楼