Web Components

概述

各种网站往往需要一些相同的模块,比如日历、调色板等等,这种模块就被称为“组件”(component)。Web Components 就是浏览器原生的组件规范。

采用组件开发,有很多优点。

(1)有利于代码复用。组件是模块化编程思想的体现,可以跨平台、跨框架使用,构建、部署和与其他 UI 元素互动都有统一做法。

(2)使用非常容易。加载或卸载组件,只要添加或删除一行代码就可以了。

(3)开发和定制很方便。组件开发不需要使用框架,只要用原生的语法就可以了。开发好的组件往往留出接口,供使用者设置常见属性,比如上面代码的heading属性,就是用来设置对话框的标题。

(4)组件提供了 HTML、CSS、JavaScript 封装的方法,实现了与同一页面上其他代码的隔离。

未来的网站开发,可以像搭积木一样,把组件合在一起,就组成了一个网站。这种前景是非常诱人的。

Web Components 不是单一的规范,而是一系列的技术组成,以下是它的四个构成。

  • Custom Elements
  • Template
  • Shadow DOM
  • HTML Import

使用时,并不一定上面四种 API 都要用到。其中,Custom Element 和 Shadow DOM 比较重要,Template 和 HTML Import 只起到辅助作用。

Custom Element

简介

HTML 标准定义的网页元素,有时并不符合我们的需要,这时浏览器允许用户自定义网页元素,这就叫做 Custom Element。简单说,它就是用户自定义的网页元素,是 Web components 技术的核心。

举例来说,你可以自定义一个叫做<my-element>的网页元素。

  1. <my-element></my-element>

注意,自定义网页元素的标签名必须含有连字符-,一个或多个连字符都可以。这是因为浏览器内置的的 HTML 元素标签名,都不含有连字符,这样可以做到有效区分。

下面的代码先定义一个自定义元素的类。

  1. class MyElement extends HTMLElement {
  2. constructor() {
  3. super();
  4. this.attachShadow( { mode: 'open' } );
  5. this.shadowRoot.innerHTML = `
  6. <style>
  7. /* scoped styles */
  8. </style>
  9. <slot></slot>
  10. `;
  11. }
  12. static get observedAttributes() {
  13. // Return list of attributes to watch.
  14. }
  15. attributeChangedCallback( name, oldValue, newValue ) {
  16. // Run functionality when one of these attributes is changed.
  17. }
  18. connectedCallback() {
  19. // Run functionality when an instance of this element is inserted into the DOM.
  20. }
  21. disconnectedCallback() {
  22. // Run functionality when an instance of this element is removed from the DOM.
  23. }
  24. }

上面代码有几个注意点。

  • 自定义元素类的基类是HTMLElement。当然也可以根据需要,基于HTMLElement的子类,比如HTMLButtonElement
  • 构造函数内部定义了 Shadow DOM。所谓Shadow DOM指的是,这部分的 HTML 代码和样式,不直接暴露给用户。
  • 类可以定义生命周期方法,比如connectedCallback()

然后,window.customElements.define()方法,用来登记自定义元素与这个类之间的映射。

  1. window.customElements.define('my-element', MyElement);

登记以后,页面上的每一个<my-element>元素都是一个MyElement类的实例。只要浏览器解析到<my-element>元素,就会运行MyElement的构造函数。

注意,如果没有登记就使用 Custom Element,浏览器会认为这是一个不认识的元素,会当做空的 div 元素处理。

window.customElements.define()方法定义了 Custom Element 以后,可以使用window.customeElements.get()方法获取该元素的构造方法。这使得除了直接插入 HTML 网页,Custom Element 也能使用脚本插入网页。

  1. window.customElements.define(
  2. 'my-element',
  3. class extends HTMLElement {...}
  4. );
  5. const el = window.customElements.get('my-element');
  6. const myElement = new el();
  7. document.body.appendChild(myElement);

如果你想扩展现有的 HTML 元素(比如<button>)也是可以的。

  1. class GreetingElement extends HTMLButtonElement

登记的时候,需要提供扩展的元素。

  1. customElements.define('hey-there', GreetingElement, { extends: 'button' });

使用的时候,为元素加上is属性就可以了。

  1. <button is="hey-there" name="World">Howdy</button>

生命周期方法

Custom Element 提供一些生命周期方法。

  1. class MyElement extends HTMLElement {
  2. constructor() {
  3. super();
  4. }
  5. connectedCallback() {
  6. // here the element has been inserted into the DOM
  7. }
  8. }

上面代码中,connectedCallback()方法就是MyElement元素的生命周期方法。每次,该元素插入 DOM,就会自动执行该方法。

  • connectedCallback():插入 DOM 时调用。这可能不止一次发生,比如元素被移除后又重新添加。类的设置应该尽量放到这个方法里面执行,因为这时各种属性和子元素都可用。
  • disconnectedCallback():移出 DOM 时执行。
  • attributeChangedCallback(attrName, oldVal, newVal):添加、删除、更新或替换属性时调用。元素创建或升级时,也会调用。注意:只有加入observedAttributes的属性才会执行这个方法。
  • adoptedCallback():自定义元素移动到新的 document 时调用,比如执行document.adoptNode(element)时。

下面是一个例子。

  1. class GreetingElement extends HTMLElement {
  2. constructor() {
  3. super();
  4. this._name = 'Stranger';
  5. }
  6. connectedCallback() {
  7. this.addEventListener('click', e => alert(`Hello, ${this._name}!`));
  8. }
  9. attributeChangedCallback(attrName, oldValue, newValue) {
  10. if (attrName === 'name') {
  11. if (newValue) {
  12. this._name = newValue;
  13. } else {
  14. this._name = 'Stranger';
  15. }
  16. }
  17. }
  18. }
  19. GreetingElement.observedAttributes = ['name'];
  20. customElements.define('hey-there', GreetingElement);

上面代码中,GreetingElement.observedAttributes属性用来指定白名单里面的属性,上例是name属性。只要这个属性的值发生变化,就会自动调用attributeChangedCallback方法。

使用上面这个类的方法如下。

  1. <hey-there>Greeting</hey-there>
  2. <hey-there name="Potch">Personalized Greeting</hey-there>

attributeChangedCallback方法主要用于外部传入的属性,就像上面例子中name="Potch"

生命周期方法调用的顺序如下:constructor -> attributeChangedCallback -> connectedCallback,即attributeChangedCallback早于connectedCallback执行。这是因为attributeChangedCallback相当于调整配置,应该在插入 DOM 之前完成。

下面的例子能够更明显地看出这一点,在插入 DOM 前修改 Custome Element 的颜色。

  1. class MyElement extends HTMLElement {
  2. constructor() {
  3. this.container = this.shadowRoot.querySelector('#container');
  4. }
  5. attributeChangedCallback(attr, oldVal, newVal) {
  6. if(attr === 'disabled') {
  7. if(this.hasAttribute('disabled') {
  8. this.container.style.background = '#808080';
  9. } else {
  10. this.container.style.background = '#ffffff';
  11. }
  12. }
  13. }
  14. }

自定义属性和方法

Custom Element 允许自定义属性或方法。

  1. class MyElement extends HTMLElement {
  2. ...
  3. doSomething() {
  4. // do something in this method
  5. }
  6. }

上面代码中,doSomething()就是MyElement的自定义方法,使用方法如下。

  1. const element = document.querySelector('my-element');
  2. element.doSomething();

自定义属性可以使用 JavaScript class 的所有语法,因此也可以设置取值器和赋值器。

  1. class MyElement extends HTMLElement {
  2. ...
  3. set disabled(isDisabled) {
  4. if(isDisabled) {
  5. this.setAttribute('disabled', '');
  6. }
  7. else {
  8. this.removeAttribute('disabled');
  9. }
  10. }
  11. get disabled() {
  12. return this.hasAttribute('disabled');
  13. }
  14. }

上面代码中的取值器和赋值器,可用于<my-input name="name" disabled>这样的用法。

window.customElements.whenDefined()

window.customElements.whenDefined()方法在一个 Custom Element 被customElements.define()方法定义以后执行,用于“升级”一个元素。

  1. window.customElements.whenDefined('my-element')
  2. .then(() => {
  3. // my-element is now defined
  4. })

如果某个属性值发生变化时,需要做出反应,可以将它放入observedAttributes数组。

  1. class MyElement extends HTMLElement {
  2. static get observedAttributes() {
  3. return ['disabled'];
  4. }
  5. constructor() {
  6. const shadowRoot = this.attachShadow({mode: 'open'});
  7. shadowRoot.innerHTML = `
  8. <style>
  9. .disabled {
  10. opacity: 0.4;
  11. }
  12. </style>
  13. <div id="container"></div>
  14. `;
  15. this.container = this.shadowRoot('#container');
  16. }
  17. attributeChangedCallback(attr, oldVal, newVal) {
  18. if(attr === 'disabled') {
  19. if(this.disabled) {
  20. this.container.classList.add('disabled');
  21. }
  22. else {
  23. this.container.classList.remove('disabled')
  24. }
  25. }
  26. }
  27. }

回调函数

自定义元素的原型有一些属性,用来指定回调函数,在特定事件发生时触发。

  • createdCallback:实例生成时触发
  • attachedCallback:实例插入HTML文档时触发
  • detachedCallback:实例从HTML文档移除时触发
  • attributeChangedCallback(attrName, oldVal, newVal):实例的属性发生改变时(添加、移除、更新)触发

下面是一个例子。

  1. var proto = Object.create(HTMLElement.prototype);
  2. proto.createdCallback = function() {
  3. console.log('created');
  4. this.innerHTML = 'This is a my-demo element!';
  5. };
  6. proto.attachedCallback = function() {
  7. console.log('attached');
  8. };
  9. var XFoo = document.registerElement('x-foo', {prototype: proto});

利用回调函数,可以方便地在自定义元素中插入HTML语句。

  1. var XFooProto = Object.create(HTMLElement.prototype);
  2. XFooProto.createdCallback = function() {
  3. this.innerHTML = "<b>I'm an x-foo-with-markup!</b>";
  4. };
  5. var XFoo = document.registerElement('x-foo-with-markup',
  6. {prototype: XFooProto});

上面代码定义了createdCallback回调函数,生成实例时,该函数运行,插入如下的HTML语句。

  1. <x-foo-with-markup>
  2. <b>I'm an x-foo-with-markup!</b>
  3. </x-foo-with-markup>

Custom Element 的子元素

用户使用 Custom Element 时候,可以在内部放置子元素。Custom Element 提供<slot>用来引用内部内容。

下面的<image-gallery>是一个 Custom Element。用户在里面放置了子元素。

  1. <image-gallery>
  2. <img src="foo.jpg" slot="image">
  3. <img src="bar.jpg" slot="image">
  4. </image-gallery>

<image-gallery>内部的模板如下。

  1. <div id="container">
  2. <div class="images">
  3. <slot name="image"></slot>
  4. </div>
  5. </div>

最终合成的代码如下。

  1. <div id="container">
  2. <div class="images">
  3. <slot name="image">
  4. <img src="foo.jpg" slot="image">
  5. <img src="bar.jpg" slot="image">
  6. </slot>
  7. </div>
  8. </div>

<template>标签

基本用法

<template>标签表示组件的 HTML 代码模板。

  1. <template>
  2. <h1>This won't display!</h1>
  3. <script>alert("this won't alert!");</script>
  4. </template>

<template>内部就是正常的 HTML 代码,浏览器不会将这些代码加入 DOM。

下面的代码会将模板内部的代码插入 DOM。

  1. let template = document.querySelector('template');
  2. document.body.appendChild(template.content);

注意,模板内部的代码只能插入一次,如果第二次执行上面的代码就会报错。

如果需要多次插入模板,可以复制<template>内部代码,然后再插入。

  1. document.body.appendChild(template.content.cloneNode(true));

上面代码中,cloneNode()方法的参数true表示复制包含所有子节点。

接受<template>插入的元素,叫做宿主元素(host)。在<template>之中,可以对宿主元素设置样式。

  1. <template>
  2. <style>
  3. :host {
  4. background: #f8f8f8;
  5. }
  6. :host(:hover) {
  7. background: #ccc;
  8. }
  9. </style>
  10. </template>

document.importNode()

document.importNode方法用于克隆外部文档的DOM节点。

  1. var iframe = document.getElementsByTagName("iframe")[0];
  2. var oldNode = iframe.contentWindow.document.getElementById("myNode");
  3. var newNode = document.importNode(oldNode, true);
  4. document.getElementById("container").appendChild(newNode);

上面例子是将iframe窗口之中的节点oldNode,克隆进入当前文档。

注意,克隆节点之后,还必须用appendChild方法将其加入当前文档,否则不会显示。换个角度说,这意味着插入外部文档节点之前,必须用document.importNode方法先将这个节点准备好。

document.importNode方法接受两个参数,第一个参数是外部文档的DOM节点,第二个参数是一个布尔值,表示是否连同子节点一起克隆,默认为false。大多数情况下,必须显式地将第二个参数设为true。

Shadow DOM

所谓 Shadow DOM 指的是,浏览器将模板、样式表、属性、JavaScript 码等,封装成一个独立的 DOM 元素。外部的设置无法影响到其内部,而内部的设置也不会影响到外部,与浏览器处理原生网页元素(比如<video>元素)的方式很像。

Shadow DOM 最大的好处有两个,一是可以向用户隐藏细节,直接提供组件,二是可以封装内部样式表,不会影响到外部。

Custom Element 内部有一个 Shadow Root。它就是接入外部 DOM 的根元素。

  1. // attachShadow() creates a shadow root.
  2. let shadow = div.attachShadow({ mode: 'open' });
  3. let inner = document.createElement('b');
  4. inner.appendChild(document.createTextNode('Hiding in the shadows'));
  5. // shadow root supports the normal appendChild method.
  6. shadow.appendChild(inner);
  7. div.querySelector('b'); // empty

上面代码中,<div>包含<b>,但是 DOM 方法无法看到它,而且页面的样式也影响不到它。

mode: 'open'表示开发者工具里面,可以看到 Custom HTML 内部的 DOM,并与之互动。mode: closed将不允许 Custom Element 的使用者与内部代码互动。

Shadow root 内部通过指定innerHTML属性或使用<template>元素,指定 HTML 代码。

Shadow DOM 内部可以通过向根添加<style>(或<link>)来设置样式。

  1. let style = document.createElement('style');
  2. style.innerText = 'b { font-weight: bolder; color: red; }';
  3. shadowRoot.appendChild(style);
  4. let inner = document.createElement('b');
  5. inner.innerHTML = "I'm bolder in the shadows";
  6. shadowRoot.appendChild(inner);

上面代码添加的样式,只会影响 Shadow DOM 内的元素。

Custom Element 的 CSS 样式内部,:root表示这个根元素。比如,Custom Element 默认是行内元素,下面代码可以改成块级元素。

  1. :host {
  2. display: block;
  3. }
  4. :host([disabled]) {
  5. opacity: 0.5;
  6. }

注意,外部样式会覆盖掉:host的设置,比如下面的样式会覆盖:host

  1. my-element {
  2. display: inline-block;
  3. }

利用 CSS 的自定义属性,可以为 Custom Element 可以被覆盖的默认样式。下面是外部样式,my-element是 Custom Element。

  1. my-element {
  2. --background-color: #ff0000;
  3. }

然后,内部可以指定默认样式,用于用户没有指定颜色的情况。

  1. :host {
  2. --background-color: #ffffff;
  3. }
  4. #container {
  5. background-color: var(--background-color);
  6. }

下面的例子是为 Shadow DOM 加上独立的模板。

  1. <div id="nameTag">张三</div>
  2. <template id="nameTagTemplate">
  3. <style>
  4. .outer {
  5. border: 2px solid brown;
  6. }
  7. </style>
  8. <div class="outer">
  9. <div class="boilerplate">
  10. Hi! My name is
  11. </div>
  12. <div class="name">
  13. Bob
  14. </div>
  15. </div>
  16. </template>

上面代码是一个div元素和模板。接下来,就是要把模板应用到div元素上。

HTML Import

基本操作

长久以来,网页可以加载外部的样式表、脚本、图片、多媒体,却无法方便地加载其他网页,iframe和ajax都只能提供部分的解决方案,且有很大的局限。HTML Import就是为了解决加载外部网页这个问题,而提出来的。

下面代码用于测试当前浏览器是否支持HTML Import。

  1. function supportsImports() {
  2. return 'import' in document.createElement('link');
  3. }
  4. if (supportsImports()) {
  5. // 支持
  6. } else {
  7. // 不支持
  8. }

HTML Import用于将外部的HTML文档加载进当前文档。我们可以将组件的HTML、CSS、JavaScript封装在一个文件里,然后使用下面的代码插入需要使用该组件的网页。

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

上面代码在网页中插入一个对话框组件,该组建封装在dialog.html文件。注意,dialog.html文件中的样式和JavaScript脚本,都对所插入的整个网页有效。

假定A网页通过HTML Import加载了B网页,即B是一个组件,那么B网页的样式表和脚本,对A网页也有效(准确得说,只有style标签中的样式对A网页有效,link标签加载的样式表对A网页无效)。所以可以把多个样式表和脚本,都放在B网页中,都从那里加载。这对大型的框架,是很方便的加载方法。

如果B与A不在同一个域,那么A所在的域必须打开CORS。

  1. <!-- example.com必须打开CORS -->
  2. <link rel="import" href="http://example.com/elements.html">

除了用link标签,也可以用JavaScript调用link元素,完成HTML Import。

  1. var link = document.createElement('link');
  2. link.rel = 'import';
  3. link.href = 'file.html'
  4. link.onload = function(e) {...};
  5. link.onerror = function(e) {...};
  6. document.head.appendChild(link);

HTML Import加载成功时,会在link元素上触发load事件,加载失败时(比如404错误)会触发error事件,可以对这两个事件指定回调函数。

  1. <script async>
  2. function handleLoad(e) {
  3. console.log('Loaded import: ' + e.target.href);
  4. }
  5. function handleError(e) {
  6. console.log('Error loading import: ' + e.target.href);
  7. }
  8. </script>
  9. <link rel="import" href="file.html"
  10. onload="handleLoad(event)" onerror="handleError(event)">

上面代码中,handleLoad和handleError函数的定义,必须在link元素的前面。因为浏览器元素遇到link元素时,立刻解析并加载外部网页(同步操作),如果这时没有对这两个函数定义,就会报错。

HTML Import是同步加载,会阻塞当前网页的渲染,这主要是为了样式表的考虑,因为外部网页的样式表对当前网页也有效。如果想避免这一点,可以为link元素加上async属性。当然,这也意味着,如果外部网页定义了组件,就不能立即使用了,必须等HTML Import完成,才能使用。

  1. <link rel="import" href="/path/to/import_that_takes_5secs.html" async>

但是,HTML Import不会阻塞当前网页的解析和脚本执行(即阻塞渲染)。这意味着在加载的同时,主页面的脚本会继续执行。

最后,HTML Import支持多重加载,即被加载的网页同时又加载其他网页。如果这些网页都重复加载同一个外部脚本,浏览器只会抓取并执行一次该脚本。比如,A网页加载了B网页,它们各自都需要加载jQuery,浏览器只会加载一次jQuery。

脚本的执行

外部网页的内容,并不会自动显示在当前网页中,它只是储存在浏览器中,等到被调用的时候才加载进入当前网页。为了加载网页网页,必须用DOM操作获取加载的内容。具体来说,就是使用link元素的import属性,来获取加载的内容。这一点与iframe完全不同。

  1. var content = document.querySelector('link[rel="import"]').import;

发生以下情况时,link.import属性为null。

  • 浏览器不支持HTML Import
  • link元素没有声明rel="import"
  • link元素没有被加入DOM
  • link元素已经从DOM中移除
  • 对方域名没有打开CORS

下面代码用于从加载的外部网页选取id为template的元素,然后将其克隆后加入当前网页的DOM。

  1. var el = linkElement.import.querySelector('#template');
  2. document.body.appendChild(el.cloneNode(true));

当前网页可以获取外部网页,反过来也一样,外部网页中的脚本,不仅可以获取本身的DOM,还可以获取link元素所在的当前网页的DOM。

  1. // 以下代码位于被加载(import)的外部网页
  2. // importDoc指向被加载的DOM
  3. var importDoc = document.currentScript.ownerDocument;
  4. // mainDoc指向主文档的DOM
  5. var mainDoc = document;
  6. // 将子页面的样式表添加主文档
  7. var styles = importDoc.querySelector('link[rel="stylesheet"]');
  8. mainDoc.head.appendChild(styles.cloneNode(true));

上面代码将所加载的外部网页的样式表,添加进当前网页。

被加载的外部网页的脚本是直接在当前网页的上下文执行,因为它的window.document指的是当前网页的document,而且它定义的函数可以被当前网页的脚本直接引用。

Web Component的封装

对于Web Component来说,HTML Import的一个重要应用是在所加载的网页中,自动登记Custom Element。

  1. <script>
  2. // 定义并登记<say-hi>
  3. var proto = Object.create(HTMLElement.prototype);
  4. proto.createdCallback = function() {
  5. this.innerHTML = 'Hello, <b>' +
  6. (this.getAttribute('name') || '?') + '</b>';
  7. };
  8. document.registerElement('say-hi', {prototype: proto});
  9. </script>
  10. <template id="t">
  11. <style>
  12. ::content > * {
  13. color: red;
  14. }
  15. </style>
  16. <span>I'm a shadow-element using Shadow DOM!</span>
  17. <content></content>
  18. </template>
  19. <script>
  20. (function() {
  21. var importDoc = document.currentScript.ownerDocument; //指向被加载的网页
  22. // 定义并登记<shadow-element>
  23. var proto2 = Object.create(HTMLElement.prototype);
  24. proto2.createdCallback = function() {
  25. var template = importDoc.querySelector('#t');
  26. var clone = document.importNode(template.content, true);
  27. var root = this.createShadowRoot();
  28. root.appendChild(clone);
  29. };
  30. document.registerElement('shadow-element', {prototype: proto2});
  31. })();
  32. </script>

上面代码定义并登记了两个元素:\和\。在主页面使用这两个元素,非常简单。

  1. <head>
  2. <link rel="import" href="elements.html">
  3. </head>
  4. <body>
  5. <say-hi name="Eric"></say-hi>
  6. <shadow-element>
  7. <div>( I'm in the light dom )</div>
  8. </shadow-element>
  9. </body>

不难想到,这意味着HTML Import使得Web Component变得可分享了,其他人只要拷贝elements.html,就可以在自己的页面中使用了。

Polymer.js

Web Components是非常新的技术,为了让老式浏览器也能使用,Google推出了一个函数库Polymer.js。这个库不仅可以帮助开发者,定义自己的网页元素,还提供许多预先制作好的组件,可以直接使用。

直接使用的组件

Polymer.js提供的组件,可以直接插入网页,比如下面的google-map。。

  1. <script src="components/platform/platform.js"></script>
  2. <link rel="import" href="google-map.html">
  3. <google-map lat="37.790" long="-122.390"></google-map>

再比如,在网页中插入一个时钟,可以直接使用下面的标签。

  1. <polymer-ui-clock></polymer-ui-clock>

自定义标签与其他标签的用法完全相同,也可以使用CSS指定它的样式。

  1. polymer-ui-clock {
  2. width: 320px;
  3. height: 320px;
  4. display: inline-block;
  5. background: url("../assets/glass.png") no-repeat;
  6. background-size: cover;
  7. border: 4px solid rgba(32, 32, 32, 0.3);
  8. }

安装

如果使用bower安装,至少需要安装platform和core components这两个核心部分。

  1. bower install --save Polymer/platform
  2. bower install --save Polymer/polymer

你还可以安装所有预先定义的界面组件。

  1. bower install Polymer/core-elements
  2. bower install Polymer/polymer-ui-elements

还可以只安装单个组件。

  1. bower install Polymer/polymer-ui-accordion

这时,组件根目录下的bower.json,会指明该组件的依赖的模块,这些模块会被自动安装。

  1. {
  2. "name": "polymer-ui-accordion",
  3. "private": true,
  4. "dependencies": {
  5. "polymer": "Polymer/polymer#0.2.0",
  6. "polymer-selector": "Polymer/polymer-selector#0.2.0",
  7. "polymer-ui-collapsible": "Polymer/polymer-ui-collapsible#0.2.0"
  8. },
  9. "version": "0.2.0"
  10. }

自定义组件

下面是一个最简单的自定义组件的例子。

  1. <link rel="import" href="../bower_components/polymer/polymer.html">
  2. <polymer-element name="lorem-element">
  3. <template>
  4. <p>Lorem ipsum</p>
  5. </template>
  6. </polymer-element>

上面代码定义了lorem-element组件。它分成三个部分。

(1)import命令

import命令表示载入核心模块

(2)polymer-element标签

polymer-element标签定义了组件的名称(注意,组件名称中必须包含连字符)。它还可以使用extends属性,表示组件基于某种网页元素。

  1. <polymer-element name="w3c-disclosure" extends="button">

(3)template标签

template标签定义了网页元素的模板。

组件的使用方法

在调用组件的网页中,首先加载polymer.js库和组件文件。

  1. <script src="components/platform/platform.js"></script>
  2. <link rel="import" href="w3c-disclosure.html">

然后,分成两种情况。如果组件不基于任何现有的HTML网页元素(即定义的时候没有使用extends属性),则可以直接使用组件。

  1. <lorem-element></lorem-element>

这时网页上就会显示一行字“Lorem ipsum”。

如果组件是基于(extends)现有的网页元素,则必须在该种元素上使用is属性指定组件。

  1. <button is="w3c-disclosure">Expand section 1</button>

参考链接