使用Shadow DOM创建Web组件

移动开发
Web Components(组件)标准是一系列最新推出的标准,它可以被用来创建可被复用的Web部件,当页面中所使用的Web部件被更新为新版本时不必修改 页面中其他任何代码。这里所说的部件,是一种可实现与用户之间的交互的可视化组件,开发者可以使用HTML代码与JavaScript脚本代码来开发这些 部件。Web Componnts标准定义如何开发这些部件。

本文概述

Web Components(组件)标准是一系列***推出的标准,它可以被用来创建可被复用的Web部件,当页面中所使用的Web部件被更新为新版本时不必修改 页面中其他任何代码。这里所说的部件,是一种可实现与用户之间的交互的可视化组件,开发者可以使用HTML代码与JavaScript脚本代码来开发这些 部件。Web Componnts标准定义如何开发这些部件。

目前为止,由于一些基本问题,导致使用HTML代码与JavaScript脚本代码开发出来的部件很难被应用在页面中,这些问题包括:一个部 件内的DOM树并没有被封装,这意味着你的样式表中的样式可能被意外地被应用到部件中,你的JavaScript脚本代码可能会修改部件中的某个部分,你 定义的ID可能会与部件内部所使用的ID相同等等。

最糟糕的是,由于部件没有被封装,如果你更新了部件,更改了其中的内部细节,你的页面上的样式表及JavaScript脚本代码可能会导致意想不到的结果。

一个Web组件通常由四个部分组成:模板、Shadow DOM、自定义元素与打包,其中Shadow DOM解决了组件在页面中的封装问题。可以结合使用这四个部分,也可以单独使用其中的一两个部分。本文介绍如何使用Shadom DOM。目前为止只有Chrome 25浏览器支持Shadow DOM,且使用时必须书写webkit前缀。

简单示例程序

通过Shadow DOM的使用,元素可以拥有一种新的被称为shadow root的节点,这时该元素被称为shadow容器。浏览器中不会渲染shadow容器中原有内容,而是渲染shadow root节点中的内容。

例如,你可以将HTML页面书写为如下所示:

  1. <button>click me</button> 
  2. <script> 
  3. var host = document.querySelector('button'); 
  4. var root = host.webkitCreateShadowRoot(); 
  5. root.textContent = '点击我'
  6. </script> 

通过这段代码,按钮中原有文字“click me”将被替换为“点击我”。请注意,在JavaScript脚本代码中,按钮的textContent属性值仍然为“click me”,而不是“点击我”,因为在DOM树中shadow root节点是被忽视的。

一个容易被违反的规则是:你不应该将页面内容安排在shadow root节点中。页面内容必须是屏幕阅读器、搜索引擎、浏览器扩展所能访问到的内容。Shadow DOM从语义上来说是没有任何意义的,它只被用来动态创建一个Web组件,而该Web组件中的任何内容也能被显示在页面中。当然,我们不是被强制使用该方 法来创建Web组件。

分离内容与展示

接下来,我们来看如何使用Shadow DOM将内容与展示进行分离。我们具有如下图所示的一个Web组件。

其样式代码与HTML页面代码如下所示(不使用Shadow DOM):

  1. <style> 
  2. .outer { 
  3.     border: 2px solid brown; 
  4.     border-radius: 1em; 
  5.     background: red; 
  6.     font-size: 20pt; 
  7.     width: 12em; 
  8.     height: 7em; 
  9.     text-align: center; 
  10. .boilerplate { 
  11.     color: white; 
  12.     font-family: sans-serif; 
  13.     padding: 0.5em; 
  14. .name { 
  15.     color: black; 
  16.     background: white; 
  17.     font-family: "宋体"; 
  18.     font-size: 30pt; 
  19.     padding-top: 0.2em; 
  20. </style> 
  21. <div class="outer"> 
  22.     <div class="boilerplate"> 
  23.         你好,欢迎来到 
  24.     </div> 
  25.     <div class="name"> 
  26.         HTML 5在线 
  27.     </div> 
  28. </div> 

因为这个Web组件没有被封装,其样式代码与HTML代码是被直接书写在样式代码与页面HTML代码中的,所以只要有人在其他地方不小心修改或重定义了该Web组件所使用的样式类代码,该组件就被破坏了。我们需要避免这种情况。

***步:隐藏展示细节

在这段代码中,我们可能已经注意到:其中有一个样式类名为name的div元素,其中显示“HTML 5在线”文字。首先,我们将该元素的HTML代码修改为如下所示:

  1. <div id="nameComponent">HTML 5在线</div> 

然后,我们将所有该Web部件用样式代码与HTML代码书写到一个id为nameComponentTemplate的template元素中:

  1. <div id="nameComponent">HTML 5在线</div> 
  2. <template id="nameComponentTemplate"> 
  3. <style> 
  4. .outer { 
  5.     border: 2px solid brown; 
  6.     border-radius: 1em; 
  7.     background: red; 
  8.     font-size: 20pt; 
  9.     width: 12em; 
  10.     height: 7em; 
  11.     text-align: center; 
  12. .boilerplate { 
  13.     color: white; 
  14.     font-family: sans-serif; 
  15.     padding: 0.5em; 
  16. .name { 
  17.     color: black; 
  18.     background: white; 
  19.     font-family: "宋体"; 
  20.     font-size: 30pt; 
  21.     padding-top: 0.2em; 
  22. </style> 
  23. <div class="outer"> 
  24.     <div class="boilerplate"> 
  25.         你好,欢迎来到 
  26.     </div> 
  27.     <div class="name"> 
  28.         HTML 5在线 
  29.     </div> 
  30. </div> 
  31. </template> 

现在,该Web组件在页面上不可见,因为我们将它移到了一个template元素中,我们可以在JavaScript脚本代码中访问该Web组件。现在,我们将它放入nameComponent元素的shadow root节点中,代码如下所示:

  1. <script> 
  2. var shadow = document.querySelector('#nameComponent').webkitCreateShadowRoot(); 
  3. var template = document.querySelector('#nameComponentTemplate'); 
  4. shadow.appendChild(template.content); 
  5. template.remove(); 
  6. </script> 

现在,该组件将仍然被显示在页面上。如果你用鼠标右击nameComponent元素并查看元素内容,你将只能看见如下所示的内容:

  1. <div id="nameComponent">HTML 5在线</div> 

由此证明,通过Shadow DOM的使用,我们可以隐藏Web组件的展示细节,因为该细节被封装在元素的shadow root节点中。

第二步:分离内容与展示

现在我们的Web组件的展示细节已经被隐藏起来了,但Web组件中的内容并没有被独立出来,因为尽管组件内容(“HTML 5在线”)被显示在了页面上,但是该内容是通过被复制在元素的shadow root节点中的方法显示出来的。如果我们要修改组件内容,我们要再一次将其复制到元素的shadow root节点中。

在HTML 中,元素是可组合的,例如你可以在一个table元素中放入一个按钮。此处我们要实现的就是这种组合:在背景色为红色的容器元素中放入一个“HTML 5在线”文字。

你可以通过一个新的被称为content的元素来自定义你的Web组件中的部分内容。该元素在Web组件中创建一个注入点,在JavaScript脚本代码中可以向该注入点中动态注入内容。

接下来,我们首先修改template元素中的代码如下所示:

  1. <template id="nameComponentTemplate"> 
  2. <style> 
  3. ... 
  4. </style> 
  5. <div class="outer"> 
  6.     <div class="boilerplate"> 
  7.         你好,欢迎来到 
  8.     </div> 
  9.     <div class="name"> 
  10.         <content></content> 
  11.     </div> 
  12. </div> 
  13. </template> 

现在我们的Web部件仍将被渲染在页面上,但是原有“HTML 5在线”文字内容将被动态注入在content元素中。

如果你需要修改该文字内容,你可以使用如下所示的代码:

  1. document.querySelector('#nameComponent').textContent = '陆凌牛'

现在我们已经实现了内容与展示的分离。内容被显示在页面中,而在Web组件内部实现内容的展示。

将内容与展示分离的好处

将内容与展示分离的好处在于:我们可以很轻松地实现对组件内容的控制。例如在上述示例中,如果需要修改“HTML 5在线”文字,我们只需修改shadow root节点中的内容(即textContent属性值)即可,不需书写其他任何代码。

如果要修改组件中的其他任何内容或样式,我们也只需要修改template元素中的样式代码或HTML代码即可:

  1. <template id="nameComponentTemplate"> 
  2. <style> 
  3. .outer { 
  4.     border: 2px solid brown; 
  5.     border-radius: 1em; 
  6.     background: red; 
  7.     font-size: 20pt; 
  8.     width: 12em; 
  9.     height: 7em; 
  10.     text-align: center; 
  11. .boilerplate { 
  12.     color: white; 
  13.     font-family: sans-serif; 
  14.     padding: 0.5em; 
  15.  .littleFontSize{     font-size: 15pt; }   
  16. .name { 
  17.     color: black; 
  18.     background: white; 
  19.     font-family: "宋体"; 
  20.     font-size: 30pt; 
  21.     padding-top: 0.2em; 
  22. </style> 
  23. <div class="outer"> 
  24.     <div class="boilerplate"> 
  25.         你好,欢迎来到 
  26.     </div> 
  27.     <div class="name"> 
  28.         <content></content> 
  29.     </div> 
  30.          <div class="boilerplate littleFontSize"> 国内首家在桌面浏览器中正式应用HTML 5技术的技术网站。     </div>      
  31. </div> 
  32. </template> 

事实上,这个好处可以说是对目前Web技术的一个重大改善,因为你只需关注组件内部的实现代码,而不需关注外部如何使用这个组件。 例如在上述示例中,我们可以在为中文页面提供的组件中书写“你好,欢迎来到”文字,而在为英文页面提供的组件中书写“Hello,welcome to”文字。

实现高级注入

在上面这个示例代码中,可以动态向content元素中注入任何内容。事实上,我们可以使用多个content元素,并且通过select属性定义每个content元素中所显示内容的样式。

例如,你可以定义一个Web组件,其中的内容如下所示:

  1. <div class='first'>示例文字1</div> 
  2. <div class='second'>示例文字2</div> 
  3. <div class='three'>示例文字3</div> 

我们可以定义一个使用CSS样式选择器的shadow root节点,其代码如下所示:

  1. <template id="nameComponentTemplate">                 
  2.     <div style="background: purple; padding: 1em;"> 
  3.         <div style="color: red;"> 
  4.             <content select=".first"></content> 
  5.         </div> 
  6.         <div style="color: yellow;"> 
  7.             <content select=".second"></content> 
  8.         </div> 
  9.         <div style="color: blue;"> 
  10.             <content select=".three"></content> 
  11.         </div> 
  12.     </div> 
  13. </template> 

在这段代码中,每一个div元素都与<content select="div">元素相匹配,<div class='first'>元素同时与<content select="first">元素相匹配,<div class='secong'>元素同时与<content select="second">元素相匹配,,<div class='three'>元素同时与<content select="three">元素相匹配。从运行结果中我们可以看出,<div class='three'>元素的背景色为紫色,文字为蓝色,这是因为我们在组件内部定义所有div元素的背景色为紫色,且内容为< content select="first">的div元素的文字颜色为蓝色的缘故。

本文小结

本文对Shadow DOM做一基础介绍。你可以通过Shadow DOM实现更为复杂的处理。例如,你可以在一个shadow容器中实现多个shadow root节点,可以在shadow root节点中放置shadow容器(即在Web组件中嵌套使用Web组件)。在Web组件标准中,包含除Shadow DOM之外的更多内容。例如通过Custom Element(定制元素)的使用,你可以使用声明的方式,而不是使用书写脚本代码的方式来创建组件。

责任编辑:徐川 来源: html5online
相关推荐

2020-09-28 14:26:42

Shadow DOMWeb组件

2022-02-10 22:24:05

DOM结构工具

2014-05-26 16:16:59

Shadow DomWeb Compone

2009-08-11 13:27:22

C#创建Web Ser

2009-12-02 14:14:06

PHP DOM-XML

2009-04-13 11:31:55

IBMdWWebService

2010-09-28 13:40:52

DOM元素

2011-05-25 17:10:39

ibmdw

2010-09-10 13:06:27

JavaScript

2013-06-08 13:29:27

Android开发DOM读取XMLXML解析

2009-12-03 09:45:20

Visual Web

2009-12-02 16:49:46

Visual Stu

2013-06-24 10:21:47

面向对象Web应用JavaScript

2013-05-22 15:43:39

谷歌web组件web开发

2023-12-05 10:03:02

Web组件开发

2010-09-28 15:27:09

JavaScript

2015-01-14 09:46:52

Google API

2024-01-05 07:38:55

2023-03-06 16:24:38

Web组件H5小程序

2010-08-31 08:59:06

marginHTML
点赞
收藏

51CTO技术栈公众号