以下是 Rob Dodson (@rob_dodson) 的客座文章。Rob 和我在 CodePen 支持上反复讨论如何在他的演示中使用 Polymer(一种 Web Components 的 polyfill,有点像)。我们最终成功地实现了它,并且这件事演变成了这篇文章。Rob,你来吧。
更新:Rob 于 2014年3月5日 更新了这篇文章,使所有内容都保持最新,因为这项技术目前发展非常迅速。
更新:再次更新于 2014年9月9日!
最近,我与一位客户合作,培训其内部团队如何构建 Web 应用程序。在此过程中,我意识到我们目前构建前端的方式非常奇怪,甚至有点问题。在很多情况下,您要么从某个文档中复制大量 HTML 代码,然后将其粘贴到您的应用程序中(Bootstrap、Foundation 等),要么在页面上散布一些必须使用 JavaScript 配置的 jQuery 插件。这让我们处于一个相当不幸的境地,不得不选择臃肿的 HTML 或神秘的 HTML,而且通常我们两者都选择。
在理想情况下,HTML 语言应该足够表达性,能够创建复杂的 UI 小部件,并且还应该具有可扩展性,以便我们开发人员可以使用自己的标签来填补任何空白。今天,这终于可以通过一组名为 Web Components 的新标准实现了。
Web Components?
Web Components 是一组标准,它们正在通过 W3C 逐步完善并逐步应用于浏览器。简而言之,它们允许我们将标记和样式捆绑到自定义 HTML 元素中。这些新元素真正令人惊奇的是,它们完全封装了其所有 HTML 和 CSS。这意味着您编写的样式始终按预期呈现,并且您的 HTML 免受外部 JavaScript 的窥探。
如果您想使用原生 Web Components,我建议您使用 Chrome,因为它具有最好的支持。从 Chrome 36 版开始,它是第一个发布所有新标准的浏览器。
一个实际的例子
想想您目前是如何实现图像滑块的,它可能看起来像这样
<div id="slider">
<input checked="" type="radio" name="slider" id="slide1" selected="false">
<input type="radio" name="slider" id="slide2" selected="false">
<input type="radio" name="slider" id="slide3" selected="false">
<input type="radio" name="slider" id="slide4" selected="false">
<div id="slides">
<div id="overflow">
<div class="inner">
<img src="images//rock.jpg">
<img src="images/grooves.jpg">
<img src="images/arch.jpg">
<img src="images/sunset.jpg">
</div>
</div>
</div>
<label for="slide1"></label>
<label for="slide2"></label>
<label for="slide3"></label>
<label for="slide4"></label>
</div>
查看 Rob Dodson (@robdodson) 在 CodePen 上的笔 CSS3 滑块
图像滑块改编自 CSScience。图片由 Eliya Selhub 提供。
这是一大块 HTML 代码,我们甚至还没有包含 CSS!但是想象一下,如果我们可以去除所有这些额外的冗余代码,并将其减少到只有重要的部分。那会是什么样子?
<img-slider>
<img src="images/sunset.jpg" alt="a dramatic sunset">
<img src="images/arch.jpg" alt="a rock arch">
<img src="images/grooves.jpg" alt="some neat grooves">
<img src="images/rock.jpg" alt="an interesting rock">
</img-slider>
还不错!我们抛弃了样板代码,剩下的只有我们关心的东西。这就是 Web Components 将允许我们做的事情。但在深入探讨细节之前,我想再讲一个故事。
隐藏在阴影中
多年来,浏览器制造商一直袖藏着一个秘密技巧。看看这个 <video>
标签,认真思考一下,仅仅一行 HTML 代码就能获得所有这些视觉效果。
<video src="./foo.webm" controls></video>
有一个播放按钮、一个滑块、时间码和一个音量滑块。很多东西您不必编写任何标记,只要您请求 <video>
,它就会出现。
但您实际看到的只是一个幻觉。浏览器制造商需要一种方法来保证他们实现的标签始终呈现相同,无论我们页面上可能已经存在哪些奇奇怪怪的 HTML、CSS 或 JavaScript。为此,他们创建了一条秘密通道,可以在其中隐藏他们的代码,并将其置于我们热切的双手之外。他们将这个秘密地方称为:Shadow DOM。
如果您碰巧正在运行 Google Chrome,则可以打开开发者工具并启用 显示用户代理 Shadow DOM
标志。这将允许您更详细地检查 <video>
元素。


在里面,您会发现隐藏了大量 HTML 代码。足够长时间地四处查看,您会发现前面提到的播放按钮、音量滑块和各种其他元素。
现在,回想一下我们的图像滑块。如果我们都可以访问 Shadow DOM 并且能够像 <video>
一样声明我们自己的标签呢?那么我们实际上就可以实现并使用我们自定义的 <img-slider>
标签了。
让我们看看如何实现这一点,使用 Web Components 的第一个支柱:模板。
模板
每个优秀的建筑项目都必须从蓝图开始,对于 Web Components,这个蓝图来自新的 <template>
标签。模板标签允许您在页面上存储一些标记,以后可以克隆和重用这些标记。如果您以前使用过像 mustache 或 handlebars 这样的库,那么 <template>
标签应该会感觉很熟悉。
<template>
<h1>Hello there!</h1>
<p>This content is top secret :)</p>
</template>
模板内的所有内容都被浏览器视为惰性。这意味着带有外部源的标签(<img>
、<audio>
、<video>
等)不会发出 http 请求,并且 <script>
标签不会执行。这也意味着模板内的任何内容都不会呈现到页面上,直到我们使用 JavaScript 激活它。
因此,创建 <img-slider>
的第一步是将所有 HTML 和 CSS 放入 <template>
中。
查看 Rob Dodson (@robdodson) 在 CodePen 上的笔 CSS3 滑块模板
完成此操作后,我们就可以将其移动到 Shadow DOM 中了。
Shadow DOM
为了真正确保我们的 HTML 和 CSS 不会对使用者产生负面影响,我们有时会求助于 iframe。它们确实可以解决问题,但您不希望在其中构建整个应用程序。
Shadow DOM 为我们提供了 iframe 最好的特性,即样式和标记封装,而几乎没有那么多的膨胀。
要创建 Shadow DOM,请选择一个元素并调用其 createShadowRoot
方法。这将返回一个文档片段,然后您可以用内容填充它。
<div class="container"></div>
<script>
var host = document.querySelector('.container');
var root = host.createShadowRoot();
root.innerHTML = '<p>How <em>you</em> doin?</p>'
</script>
Shadow Host
在 Shadow DOM 术语中,您在其上调用 createShadowRoot
的元素被称为 Shadow Host。它是唯一对用户可见的部分,也是您要求用户向您的元素提供内容的地方。
如果您考虑我们之前提到的 <video>
标签,<video>
元素本身就是 Shadow Host,而内容是您在其内部嵌套的标签。
<video>
<source src="trailer.mp4" type="video/mp4">
<source src="trailer.webm" type="video/webm">
<source src="trailer.ogv" type="video/ogg">
</video>
Shadow Root
由 createShadowRoot
返回的文档片段称为 Shadow Root。Shadow Root 及其后代对用户隐藏,但当浏览器看到我们的标签时,它实际上将呈现这些内容。
在 <video>
示例中,播放按钮、滑块、时间码等都是 Shadow Root 的后代。它们显示在屏幕上,但它们的标记对用户不可见。
阴影边界
阴影根内部的任何 HTML 和 CSS 都受到称为**阴影边界**的无形屏障的保护。阴影边界阻止父文档中的 CSS 渗透到阴影 DOM,并且还阻止外部 JavaScript 遍历到阴影根。
翻译:假设您在阴影 DOM 中有一个样式标签,该标签指定所有 h3 应具有红色的color
。同时,在父文档中,您有一个样式,该样式指定 h3 应具有蓝色的color
。在这种情况下,出现在阴影 DOM 内部的 h3 将为红色,而阴影 DOM 外部的 h3 将为蓝色。由于我们的朋友阴影边界,这两个样式将彼此忽略。
并且,如果在某个时刻,父文档开始查找带有$('h3')
的 h3,则阴影边界将阻止对阴影根的任何探索,并且选择将仅返回阴影 DOM 外部的 h3。
这种级别的隐私是我们多年来梦寐以求并一直在努力解决的问题。说它将改变我们构建 Web 应用程序的方式是轻描淡写。
阴影滑块
要将我们的img-slider
放入阴影 DOM,我们需要创建一个阴影宿主并用我们模板的内容填充它。
<template>
<!-- Full of slider awesomeness -->
</template>
<div class="img-slider"></div>
<script>
// Add the template to the Shadow DOM
var tmpl = document.querySelector('template');
var host = document.querySelector('.img-slider');
var root = host.createShadowRoot();
root.appendChild(document.importNode(tmpl.content, true));
</script>
在本例中,我们创建了一个div
并为其指定了类img-slider
,以便它可以充当我们的阴影宿主。
我们选择模板并使用document.importNode
对其内部进行深度复制。然后将这些内部内容附加到我们新创建的阴影根。
如果您使用的是 Chrome,您实际上可以在以下笔中看到它的工作原理。
查看 Rob Dodson 的笔 CSS3 滑块阴影 DOM(@robdodson)在 CodePen 上
插入点
此时,我们的img-slider
位于阴影 DOM 中,但图像路径是硬编码的。就像嵌套在<video>
内的<source>
标签一样,我们希望图像来自用户,因此我们必须邀请他们从阴影宿主中获取。
要将项目拉入阴影 DOM,我们使用新的<content>
标签。<content>
标签使用 CSS 选择器从阴影宿主中挑选元素并将其投影到阴影 DOM 中。这些投影被称为**插入点**。
为了方便起见,我们假设滑块仅包含图像,这样我们就可以使用img
选择器创建一个插入点。
<template>
...
<div class="inner">
<content select="img"></content>
</div>
</template>
因为我们使用**插入点**将内容投影到 Shadow DOM 中,所以我们还需要使用新的::content
伪元素来更新我们的 CSS。
#slides ::content img {
width: 25%;
float: left;
}
如果您想了解有关 Shadow DOM 添加的新 CSS 选择器和组合器的更多信息,请查看我整理的这份备忘单。
现在我们准备填充我们的img-slider
了。
<div class="img-slider">
<img src="images/rock.jpg" alt="an interesting rock">
<img src="images/grooves.jpg" alt="some neat grooves">
<img src="images/arch.jpg" alt="a rock arch">
<img src="images/sunset.jpg" alt="a dramatic sunset">
</div>
这真的很酷!我们减少了用户看到的标记数量。但为什么要止步于此?我们可以更进一步,将此img-slider
变成它自己的标签。
自定义元素
创建您自己的 HTML 元素听起来可能令人生畏,但实际上非常简单。在 Web Components 中,这个新元素是一个**自定义元素**,并且只有两个要求:它的名称必须包含一个连字符,并且它的原型必须扩展HTMLElement
。
让我们看看它是如何工作的。
<template>
<!-- Full of image slider awesomeness -->
</template>
<script>
// Grab our template full of slider markup and styles
var tmpl = document.querySelector('template');
// Create a prototype for a new element that extends HTMLElement
var ImgSliderProto = Object.create(HTMLElement.prototype);
// Setup our Shadow DOM and clone the template
ImgSliderProto.createdCallback = function() {
var root = this.createShadowRoot();
root.appendChild(document.importNode(tmpl.content, true));
};
// Register our new element
var ImgSlider = document.registerElement('img-slider', {
prototype: ImgSliderProto
});
</script>
Object.create
方法返回一个扩展HTMLElement
的新原型。当解析器在文档中找到我们的标签时,它会检查它是否有一个名为createdCallback
的方法。如果它找到此方法,它将立即运行它。这是一个进行设置工作的好地方,因此我们创建一些 Shadow DOM 并将我们的模板克隆到其中。
我们将标签名称和原型传递给document
上的一个新方法,称为registerElement
,之后我们就可以开始了。
现在我们的元素已注册,可以使用几种不同的方法。第一种也是最直接的方法是在我们的 HTML 中的某个地方使用<img-slider>
标签。但我们也可以调用document.createElement("img-slider")
,或者可以使用document.registerElement
返回并存储在ImgSlider
变量中的构造函数。您可以选择您喜欢的样式。
支持
构成 Web Components 的各种标准的支持令人鼓舞,并且一直在不断改进。此表说明了我们目前所处的位置。

但是,不要因为某些浏览器不支持而阻止您使用它们!Mozilla 和 Google 的聪明人一直在努力构建 polyfill 库,这些库可以将对 Web Components 的支持偷偷带入**所有现代浏览器**!这意味着您今天就可以开始使用这些技术并向编写规范的人员提供反馈。该反馈非常重要,因此我们最终不会得到难用且难以使用的语法。
让我们看看如何使用 Google 的 Web Components 库Polymer重写我们的img-slider
。
Polymer 来救援!
Polymer 向浏览器添加了一个新标签<polymer-element>
,该标签会自动将模板转换为阴影 DOM 并为我们注册自定义元素。我们只需要告诉 Polymer 使用什么名称作为标签,并确保我们包含了我们的模板标记。
查看 Chris Coyier 的笔 Polymer 滑块(@chriscoyier)在 CodePen 上。
我发现使用 Polymer 创建元素通常更容易,因为库中内置了许多优点。这包括元素和模型之间的双向绑定、自动节点查找以及对 Web 动画等其他新标准的支持。此外,polymer-dev 邮件列表上的开发人员非常活跃且乐于助人,这在您初学时非常棒,并且StackOverflow 社区也在不断发展。
这只是 Polymer 可以做的事情的一个小例子,因此请务必访问其项目页面并查看 Mozilla 的替代方案X-Tag。
问题
任何新标准都可能存在争议,在 Web Components 的情况下,它们似乎特别两极分化。在结束之前,我想就过去几个月我听到的一些反馈进行讨论,并给出我的看法。
天哪,它是 XML!!!
我认为当开发人员第一次看到自定义元素时,最让他们害怕的事情可能是它会将文档变成一大堆 XML 的想法,页面上的所有内容都具有某种定制的标签名称,并且以这种方式,我们将使网络几乎无法阅读。这是一个合理的论点,所以我决定踢蜂窝,并在Polymer 邮件列表中提出它。
来回讨论很有意思,但我认为普遍共识是,我们只能通过实验来了解哪些方法有效,哪些无效。使用像<img-slider>
这样的标签名是否更好、更语义化,或者我们目前的“div 汤”是唯一应该使用的方式?Alex Rusell撰写了一篇关于此主题的非常有见地的文章,我建议大家在做出决定之前花时间阅读一下。
SEO
目前尚不清楚爬虫对自定义元素和 Shadow DOM 的支持程度如何。Polymer 的常见问题解答中提到
搜索引擎已经处理了很长一段时间的基于 AJAX 的应用程序。远离 JS 并更具声明性是一件好事,并且通常会使事情变得更好。
Google 网站管理员博客最近宣布Google 爬虫会在索引页面之前执行页面上的 JavaScript。使用像Fetch as Google这样的工具,可以让你看到爬虫在解析你的网站时看到了什么。一个很好的例子是Polymer 网站,它使用自定义元素构建,并且可以在 Google 中轻松搜索。
我从与 Polymer 团队成员的交流中了解到的一点建议是,尽量确保自定义元素内的内容是静态的,而不是来自数据绑定。
<!-- probably good -->
<x-foo>
Here is some interesting, and searchable content...
</x-foo>
<!-- probably bad -->
<x-foo>
{{crazyDynamicContent}}
</x-foo>
<!-- also probably bad -->
<a href="{{aDynamicLink}}">Click here</a>
公平地说,这不是一个新问题。基于 AJAX 的网站已经处理这个问题几年了,值得庆幸的是,有一些解决方案。
可访问性
显然,当你在秘密的 Shadow DOM 沙盒中隐藏标记时,可访问性问题变得非常重要。Steve Faulkner 研究了 Shadow DOM 中的可访问性,并且似乎对他的发现感到满意。
初步测试结果表明,在完全位于 Shadow DOM 内的内容中包含 ARIA 角色、状态和属性可以正常工作。可访问性信息通过可访问性 API 正确公开。屏幕阅读器可以无障碍地访问 Shadow DOM 中的内容。
Marcy Sutton* 也撰写了一篇帖子探讨了这个主题,她在其中解释道
Web Components(包括 Shadow DOM)是可访问的,因为辅助技术会将页面呈现为已渲染的页面,这意味着整个文档都被读取为“一棵快乐的树”。
*Marcy 还指出,我在本文中构建的 img-slider 无法访问,因为我们的 CSS 标签技巧使其无法通过键盘访问。如果你打算在项目中重用它,请记住这一点。
当然,在前进的道路上会遇到一些障碍,但这听起来是一个非常好的开始!
样式标签?嗯,不,谢谢。
不幸的是,<link>
标签在 Shadow DOM 中不起作用,这意味着引入外部 CSS 的唯一方法是通过@import
。换句话说,<style>
标签——目前——是不可避免的。*
请记住,我们正在讨论的样式仅与组件相关,而我们之前已经接受过训练,倾向于使用外部文件,因为它们通常会影响我们的整个应用程序。因此,如果所有这些样式都只作用于一个实体,那么在元素内部放置一个<style>
标签是不是一件坏事?我个人认为是可以的,但是如果能有外部文件的选项会非常好。
* 除非你使用 Polymer,它使用 XHR 绕过了此限制。
现在轮到你了
由我们来决定这些标准应该走向何方,以及哪些最佳实践将指导它们。尝试一下Polymer,并查看 Mozilla 对 Polymer 的替代方案X-Tag(它支持一直到 Internet Explorer 9)。
此外,请务必联系Google 的开发人员和Mozilla,他们正在推动这些标准的发展。我们需要你的反馈才能将这些工具塑造成我们都希望使用的工具。
虽然仍然存在一些不足之处,但我认为 Web Components 最终将带来一种新的应用程序开发风格,更类似于将乐高积木拼搭在一起,而不是我们目前的方法,后者往往充斥着过多的样板代码。我对这一切的走向感到非常兴奋,期待着未来可能带来的变化。
这里的内容真的很棒。朝着模块化方向迈出的又一步。这与元素查询相结合,可能会非常强大。
一个小错误:看起来支持表与之关联的数字是错误的。[管理员说明]:已修复。
抱歉,伙计们。我刚给 Chris 发了一条消息。支持表暂时在这里。
嘘!浏览器支持表是错误的图片。
我之前一直对学习 Shadow DOM 感兴趣,这篇文章对我来说是一个很好的起点。我迫不及待地想看看我们能从这里走向何方。
顺便说一下,浏览器支持图片显示的是视频 Shadow DOM。
那么现在哪个支持度更高,x-tags 还是 polymer?另外,为什么他们不直接给我们提供 polyfills 和功能,而排除所有额外的元素呢?Web Components 的目的不正是让我们自己编写并添加自己的语义吗?或者我误解了这一点。无论如何,感谢这篇文章,它解答了我很多问题!
X-Tags 使用了一些 Polymer polyfills,因此这两个项目密切相关。X-Tags 为 IE9 添加了额外的支持,所以如果你需要在这个平台上工作,那么 X-Tags 将是你的最佳选择。
如果你愿意,你可以只使用 polyfills。Polymer 将它们分成两个部分。platform.js 是所有 polyfills,polymer.js 是所有框架部分(数据绑定等)。如果只需要一两个东西,你也可以运行各个 polyfills。
@Rob Dodson 谢谢,我不知道它们是分开的。不过我还有一个问题。即使他们最终允许你使用标签来引用 CSS,由于 Shadow DOM 不会泄露样式,你是否必须使用多个标签,从而导致由于多个请求而导致页面加载速度变慢?或者我错了/他们是否正在解决这个问题。
在 Mac OS 10.6.8 上的 Chrome 30 中,Polymer CodePen 无法渲染其结果。
这看起来是一项即将到来的优秀技术!我为一所网络大学工作,我们的课程媒体重复使用了一些非常适合此模型的组件,这使得生产效率大大提高。
我使用的是 Chrome 30,它对我有用。虽然我确实看到它有一次显示为空白。可能需要刷新一下。
你提到 IE 不支持这些内容,但你的非 Polymer CodePen 在 IE 11 中运行得很好。那么 IE 的支持情况如何?
嗯,这很奇怪……
据我所知,微软还没有实现任何规范。我与微软人员讨论过此事,他们也在公开推文中表示,他们正在关注 Web Components,但尚未计划实现它们。我认为您可以在这里关注他们对 Shadow DOM 的支持。
可能是 IE11 将 template 标签视为 HTMLUnknownElement 并忽略它。然后将其余样式应用于其中的标签。我没有 IE11 的副本可以测试,但如果情况如此,那就是偶然的渐进增强 :)
一如既往的精彩文章!
关于 SEO,我们将在 polymer-project.org 上发布一个视频,它比 FAQ 条目包含更多内容。当前的答案不够充实。
关于 shadow dom:FWIW,我最后听到的消息是,规范制定者正在考虑重新引入 addStyleSheet()。Polymer 为您做的一件事是将您的转换为内联样式并在元素中使用这些规则。这简化了开发,您无需了解 shadow dom 的额外细节。当我们说“Polymer 的语法糖”时,这是一个很好的例子。它使构建 Web Components 变得更容易。
Rob 提到 CSS 只能通过模板代码中的 style 标签应用,目前不支持 link 标签。我知道可以通过 CSS 伪元素选择器更改 shadow DOM(例如视频标签控件等),如这篇上一篇文章所述。Web Components 也可能吗?
当然可以!我没有涉及 Shadow DOM 的样式设置,因为它是一个非常大的话题,但有很多方法可以实现。我写了几篇关于这个主题的文章
Shadow DOM 样式设置第 1 部分
Shadow DOM 样式设置第 2 部分
首先,文章很棒!
您在上述问题列表中没有讨论安全性。具体来说,我难以理解 Web Components 如何与 iframe 安全模型相适应。
JS 安全性/隔离:如果您的第三方小部件关联了数据,您仍然需要加载 iframe 才能执行 JS 或访问存储,而不会让底层页面访问,对吗?
HTML 安全性/隔离:如果渲染的小部件 HTML 包含您不想公开给底层页面的敏感信息,那么,同样,您需要将其包装在 iframe 中。对吗?
嘿,Jared,
我认为 Web Components 在 JS 或 HTML 安全性方面没有添加任何新内容,因此您提到的所有现有规则仍然适用。
Rob,感谢分享,这真的很令人兴奋!您激励我为 IE7/IE8 做一些工作。
我编写了一个概念验证,作为针对旧版浏览器的可能的 polyfill/替代解决方案。
我的代码采用了与“标准”完全不同的路线,但我希望实现一些相同的结果,但在旧版本的 IE 中实现。我现在只实现了一些基本功能,但我的代码可以改进以添加您描述的其他一些不错的功能。也许有人可以提取我的代码中的有用部分并创建一个完全跨浏览器兼容的 polyfill。
您能否看一看这里,并告诉我您的想法?
http://www.smartmultimedia.com.au/web_components/
这是将 Web Components 添加到页面的唯一 HTML 标记
这真的很酷,但我希望
<style>
标签问题得到解决。理想情况下,我希望仍然能够在我的全局最小化 CSS 文件中使用某种特殊 CSS 选择器来为这些组件设置样式。伙计,史上最棒的头像
<style>
标签主要用于组件作者。作者可以公开多种方法,供使用者从外部访问和设置元素的样式。这些样式将与应用程序的其余 CSS 一起使用。我在主题的较高位置发布了几篇关于元素样式设置的文章链接。我同意能够为所有内容使用外部文件会很棒,而且浏览器开发人员似乎正在努力实现这一点,但这确实很棘手,因为 Shadow DOM 和 HTML Imports 引入了许多新场景。
一般来说,Web Components 是一种黑盒。样式设置是作者的职责,但可以进行自定义,这里您可以看到我如何为我的组件库执行此操作。
所有主要浏览器都支持 Polymer 吗?我不认为它已经得到了广泛支持。
Polymer 在 Chrome、FF、Opera、IE 10+ 和 Safari 6+ 中运行
非常有趣的文章。我可以预见到类似于我们在 jQuery 中了解到的 HTML“库”。
但是由于这可能不会很快进入 IE,我怀疑我是否有机会使用它。
这就是 Polymer 和 X-Tags 的作用。它们旨在将支持偷偷带入不兼容的浏览器。我认为这两个库与 jQuery 类似。
我喜欢这种东西!当它变得更加标准化时,将会非常有趣,但与此同时,您可以通过 AngularJS 指令创建这种类型的精确内容。
是的,那是真的。我知道 Angular 团队正在关注 Web Components,希望他们在未来的版本中能够更多地利用它们。我可以预见到未来指令会被组件取代。
从模块化角度来看,我可以看到一些优势。它将使共享小部件变得更加容易。
但是我有点担心这将等同于通过将杂物塞进壁橱来打扫房间。“你看不到它,所以它一定很干净,对吧?”HTML 最好和最坏的地方在于它是完全自由形式的。此外,它是一种非常宽容的语言,许多语法错误都不会被捕获。
如果对生成的代码有更严格的语法规则,我会对这种解决方案更有信心。这样,人们就可以使用 Web Components,知道存在一定水平的质量。(想想 Rails 及其“约定优于配置”的理念)
无论如何,Web Components 的发展都将是一件有趣的事情。
这听起来很像 XHTML。HTML 如此宽容是一件好事!它使许多人,而不仅仅是铁杆编码员,能够轻松发布和共享信息。
但关于您提到的质量问题,我认为我们现在已经在 JS 库领域处理这个问题了。我们更喜欢编写良好、积极开发且代码库整洁的库。Web Components 也不会有什么不同。
我理解您关于 HTML 规则更严格的观点。正如我在文章中提到的,HTML 的宽容性是福也是祸。这取决于作者。Web Components 的可移植性也很吸引人。
我理解您关于高质量库自然浮出水面的观点。但凭借当今的众包思维,仍然有一些非常糟糕的代码片段在流传。我认为总的来说,社区将自行管理,但我仍然担心,我们只是通过隐藏不良代码并使其难以访问来掩盖它。
我预见到自定义元素的一个问题是,它会给新的 Web 开发人员带来一些困惑。如果他们查看某人网页上的源代码,他们如何知道哪些元素是标准的,哪些是自定义的?我们应该鼓励作者在元素名称前使用“x-”前缀来表明它们是非标准 HTML 元素,或者可能在 Web Components 规范中要求这样做。
此外,我注意到自定义元素是用 JavaScript 创建的。如果用户禁用了 JavaScript 会怎样?他们将无法看到自定义元素的任何内容。在第一次加载页面时,在创建自定义元素的 JavaScript 加载之前,用户体验会是什么样的?例如,在
img-slider
元素中,在元素加载并运行之前,用户是否只会看到页面上的一行四个img
元素?规范要求所有自定义元素的标签名称中都包含连字符“ - ”。这就是您如何判断它们是非标准元素的方法。最初,如果我记得没错,他们实际上尝试过“x-”方法,但开发人员发现一遍遍地写“x”很烦人,而连字符可以传达相同的信息。
许多 HTML5 标准都严重依赖 JavaScript,因此如果没有它,你将破坏的不仅仅是 Web Components。老实说,我不知道浏览器中禁用 JavaScript 的功能还能存在多久。Firefox 23 已经移除了在设置中禁用 JavaScript 的功能(尽管我仍然认为你可以在 about:flags 中做到这一点)。如果你的用户大量禁用 JavaScript,那么你可能不希望使用 Web Components。
我在本文中没有提到 HTML Imports,但是我在我的博客上写过关于它们的文章,Eric Bidelman 也在 HTML5 Rocks 上发表了一篇关于它们的博文。 通常,你使用
<link rel="import">
标签在页面顶部导入元素。Imports 的加载方式与 CSS 相同,因此不会出现 FOUC(闪烁问题)。非常棒,Rob,我喜欢。值得一读。
谢谢,很高兴你喜欢!
几周前我参加了 Google 澳大利亚的聚会。Alex Danilo 提供了他正在讲解的演示文稿的链接。我认为这在这里也有帮助。
http://alex-webcomponents.appspot.com
谢谢 Steven。这是一个非常棒的演示文稿,我之前在刚接触这个主题的时候用过它。我要指出的一件事是,
<element>
标签已被移除,因此你无法再以这种方式声明自定义元素。这是一个很大的变化,很多现有的文章和演示文稿仍然使用它,因为规范在如此短的时间内发生了很大的变化。我制作了一个幻灯片演示文稿,阐明了一些变化。 特别是
<element>
标签的移除,生命周期回调的更新命名法,以及从 ::pseudo 到 ::part 选择器的更改。事实上,::part 最近再次更改为 ^ 和 ^^(“帽子和猫”)选择器。我需要写一篇关于这方面的博文,并将其发布到此评论线程中 :)精彩的博文,我喜欢这类内容,你的博客很棒,Rob,我完整地阅读了你的博客,内容非常有趣且易于理解,做得非常好。
首先,你这里有一个非常好的 HTML 滑块示例…… :)
我对 HTML5 如今能够实现的功能感到惊讶,而你展示的这些新的 Web Components 将进一步改进它。我认为有了它们,Flash 与 HTML 之战终于有了赢家;)
谢谢!
很久以前我听说过 @key-frame,但我没想到它像发布的那样简单,我感到很幸运,感谢 Chris 发布这篇文章。
嗨,这有点跑题了,但我想知道博客是否使用所见即所得编辑器,或者你是否必须手动使用 HTML 进行编码。
我很快就要开始一个博客,但没有编码经验,所以我想向有经验的人寻求建议。
任何帮助都会不胜感激!
Safari 支持 Shadow DOM 吗?你确定吗?这与我找到的所有其他来源相矛盾。
在 5 月份,他们谈论的是从 Webkit 中移除代码,因为在 Blink 分裂之后,没有一个端口使用它。
是的,这有点奇怪。
webkitCreateShadowRoot
方法在当前版本的 Safari 中有效,并且允许你在 Shadow Root 文档片段中隐藏内容。但正如你指出的那样,Safari 团队正在讨论移除允许此功能的基础代码。因此,它在今天技术上有效,但明天可能无效。我最近在 Web Apps WG 邮件列表中看到了一些来自 Apple 人员的讨论,涉及自定义元素,因此我希望能看到他们转变态度。
不错的文章,谢谢!Web Components 和 Shadow DOM 听起来很棒,不过对我来说,问题是嵌套。我们构建组件是为了简化我们的工作,并且我们通过无限地组合更简单的组件来构建复杂的组件。从这篇文章中,我还没有看到 Shadow DOM 将如何实现这一点。
嗨,Tim,
<content>
标签允许你将 Web Components 嵌套在另一个 Web Components 中,并使其整体渲染效果如你预期的那样。还有一个我们没有介绍的<shadow>
标签。为了保持文章的长度,我没有深入探讨这个主题,但是 Dominic Cooney 和 Eric Bidelman 在他们的 HTML5 Rocks 博文中对这些主题进行了很好的解释:Shadow DOM 101,Shadow DOM 301ShadowDom 最有趣的一点是 CSS 隔离。Web Components 的 CSS 规则不应该影响外部(以及可能内部)的 HTML。那么,在一个未隔离的 Web Components 中使用像
A { color: red !important;}
这样的规则会怎么样?这是我在开发WebFragments时遇到的主要难题之一。即使没有 Shadow DOM,嵌套 Web Components 也是可能的,这取决于它的实现方式。
人们需要接受这是完全可以接受的。从技术上讲,没有任何问题,它甚至不违反最佳实践。
很棒的文章。不过我很好奇一件事。
在**插入点**部分,你说
如果你不做出这个假设,你将如何处理插入?
我认为如果你使用的是原生 Web Components,你可能需要在 JavaScript 中构建这些部分,并在 createdCallback 期间将它们弹出到模板中。或者每个幻灯片都可以是它自己的自定义元素,然后你可以将它们嵌套在
<img-slider>
标签中。如果你使用的是 Polymer,你可能可以使用模板重复来找到解决方案。
所以,我想有几种方法可以解决这个问题。我想让示例尽可能简单,以免让大家感到困惑。这就是我决定那样手动编码的原因。
我就是这么想的……但是如果是这样的话,我不确定我是否能看到 Web Components 如何优于例如 jQuery 插件。并不是说这不是一件很酷的事情,但我认为 Web Components 仍然需要一些进化。
也许仅仅是因为 Web Components 还处于非常年轻的阶段,或者也许我需要更多地了解它。无论如何,感谢你的文章。非常有趣。
是否必须仅与 Polymers 和 X-tags 库一起使用 Web Components……?
嗨!我来自未来,想说请、请不要这么做。我在一家公司工作,该公司在过去某个时间创建了这些所谓的“小部件”,它们封装了一堆标记/功能,其想法是只需将它们放入页面中,它们就能正常工作!问题是,它们永远无法开箱即用地完全按照我们想要的方式工作,我们必须处理许多相互依赖且方式神秘的不同文件。我完全赞同我们行业最新的和最棒的技术,但这种功能的黑盒化并不是我们想要的。类似事物 的可维护性是一场噩梦。这些总是过度设计的……因为,好吧,“用户”开发人员永远不会看到后台的所有代码,对吧?错。他们需要看到,并且他们最终会诅咒你的名字。让我们扼杀它于萌芽状态。
来自未来的这个声音讲得很有道理。
嗨,Rob,你有没有在codeopen.io上添加过Polymer元素?我想创建一个我们创建的Polymer元素的Pen。它是一个完整的JavaScript预加载器(没有gif动画)。https://github.com/Urucas/priloader。谢谢
快速提问,请。也许我读/快速浏览了一下,但如果这里的关键思想之一是模块化以及能够自己开发然后(理想情况下,我假设)与他人分享,那么是否会出现命名冲突。
就像有人上面提到的使用x-作为前缀一样,是否应该有一些机制来缓解命名空间问题?
或者这很小/不是问题,我只是因为世界杯开始而过于兴奋而无法正常思考?