http://blog.jobbole.com/77837/

原文出处: 徐飞(@民工精髓V)

搞前端时间比较长的同学都会知道一个东西,那就是HTC(HTML Components),这个东西名字很现在流行的Web Components很像,但却是不同的两个东西,它们的思路有很多相似点,但是前者已是昨日黄花,后者方兴未艾,是什么造成了它们的这种差距呢?

HTML Components的一些特性

因为主流浏览器里面只有IE支持过HTC,所以很多人潜意识都认为它不标准,但其实它也是有标准文档的,而且到现在还有链接,注意它的时间!

http://www.w3.org/TR/NOTE-HTMLComponents

我们来看看它主要能做什么呢?

它可以以两种方式被引入到HTML页面中,一种是作为“行为”被附加到元素,使用CSS引入,一种是作为“组件”,扩展HTML的标签体系。

行为

行为(Behavior)是在IE5中引入的一个概念,主要是为了做文档结构和行为的分离,把行为通过类似样式的方式隔离出去,详细介绍在这里可以看:

http://msdn.microsoft.com/en-us/library/ms531079(v=vs.85).aspx

行为里可以引入HTC文件,刚才的HTC规范里就有,我们把它摘录出来,能看得清楚一些:

engine.htc

1
2
3
4
5
6
7
8
9
10
11
12
13
<HTML xmlns:PUBLIC="urn:HTMLComponent">
<PUBLIC:EVENT NAME="onResultChange" ID="eventOnResultChange" />
 
<SCRIPT LANGUAGE="JScript">
 
function doCalc()
{
   :
   oEvent = createEventObject();
   oEvent.result = sResult;
   eventOnResultChange.fire (oEvent);
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<HTML xmlns:LK="urn:com.microsoft.htc.samples.calc">
<HEAD>
<STYLE>
   LK\:CALC    { behavior:url(engine.htc); }
</STYLE>
</HEAD>
 
<LK:CALC ID="myCalc" onResultChange="resultWindow.innerText=window.event.result">
<TABLE>
<TR><DIV ID="resultWindow" STYLE="border: '.025cm solid gray'" ALIGN=RIGHT>0.</DIV></TR>
<TR><TD><INPUT TYPE=BUTTON VALUE=" 7 "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" 8 "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" 9 "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" / "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" C "></TD>
</TR>
<TR><TD><INPUT TYPE=BUTTON VALUE=" 4 "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" 5 "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" 6 "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" * "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" % " DISABLED></TD>
</TR>
<TR><TD><INPUT TYPE=BUTTON VALUE=" 1 "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" 2 "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" 3 "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" - "></TD>
    <TD><INPUT TYPE=BUTTON VALUE="1/x" DISABLED></TD>
</TR>
<TR><TD><INPUT TYPE=BUTTON VALUE=" 0 "></TD>
    <TD><INPUT TYPE=BUTTON VALUE="+/-"></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" . "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" + "></TD>
    <TD><INPUT TYPE=BUTTON VALUE=" = "></TD>
</TR>
 
</TABLE>
</LK:CALC>
</HTML>

这是一个计算器的例子,我们先大致看一下代码结构,是不是很清晰?再看看现在用jQuery,我们是怎么实现这种东西的:是用选择器选择这些按钮, 然后添加事件处理函数。注意你多了一步选择的过程,而且,整个过程混杂了声明式和命令式两种代码风格。如果按照它这样,你所有的JS基本都丢在了隔离的不 相关的文件中,整个是一个配置的过程,分离得很干净。

除了这种计算器,还有规范文档中举例的改变界面展示,或者添加动画之类,注意它们的切入点,都是相当于附加在特定选中元素上的行为,即使DOM不给JS暴露任何选择器,也毫无影响,因为它们直接就通过CSS的选择器挂到元素上了。

这种在现在看来,意义不算明显,现在广为使用的先选择元素再添加事件,也是不错的展现和行为分离方式。

但另外一种使用方式就不同了。

组件

狭义的HTML5给我们带来了什么?是很多新增的元素标签,比如section,nav,acticle,那这些东西跟原先直接用div实现的,好处在哪里呢?在于语义化。

所谓语义化,就是一个元素能清晰表达自己是干什么的,不会让人有歧义,像div那种,可以类比成是一个Object,它不具体表示什么东西,但可以当成各种东西来用。而nav一写,就知道,它是导航,它就像有class定义的一个实体类,能表达具体含义。

那么,原有的HTML元素显然是不够的,因为实际开发过程中要表达的东西显然远远超出这些元素,比如日历,这种东西就没有一个元素用来描述它,更不用说在一些企业应用中可能会出现的树之类复杂控件了。

不提供原生元素,对开发造成的困扰是代码写起来麻烦,具体可以看之前我在知乎的一个回复,第三点:

http://www.zhihu.com/question/22426434/answer/21433867

所以,大家都想办法去提供自己的扩充元素的方式,现在我们是知道典型的有angularjs,polymer,但很早的时候也不是没有啊:

http://msdn.microsoft.com/en-us/library/ms531076(v=vs.85).aspx

看,这就是HTC的添加自定义元素的方式,每个元素可以定义自己对外提供的属性、方法,还有事件,自己内部可以像写一个新页面一样,专注于实现功能。而且你发现没有,它考虑得很长远,提供了命名空间,防止你在一个页面引入两个不同组织提供的同名自定义元素。

这个东西就可以称为组件了,它跟外界是完全隔离的,外界只要把它拿来就可以用,就像用原生元素一样,用选择器选择,设置属性,调用方法,添加事件处理等等,而且,注意到没有,它的属性是带get和set的,这是多么梦寐以求的东西!

正是因为它这么好用,所以在那个时代,我们用它干了很多东西,封装了各种基础控件,比如树,数据表格,日期选择,等等,甚至当时也有人嫌弃浏览器原生select和radio不好看,用这么个东西,里面封装了图片来模拟功能,替换原生的来用。

当时也有人,比如我在04年就想过,能不能把这些扩大化,扩展到除了基础控件之外的地方,把业务的组件也这么搞一下,一切皆组件,多好?

但有些事情我直到后来很久以后才想明白,基于业务的端到端组件虽然写起来很方便,却是有致命缺陷的。

到这里为止,对HTML Components的回顾告一段落,也不讨论它为什么就没了之类,这里面争议太大,我只想谈谈从这里面,能看到Web Components这么个大家寄予厚望的新标准需要面对一些什么问题。

Web Components的挑战

以下逐条列出,挨个说明,有的已经有了,有的差一些,有的没有,不管这么多,总之谈谈我心目中的这个东西应当是怎样的。

自定义元素标签支持命名空间

原因我前面已经说了,可能会有不同组织实现同类功能的组件,存在于同一个页面内,引起命名歧义,所以我想了很久,还是觉得有前缀比较好:

1
2
<yours:ComponentA></yours:ComponentA>
<his:ComponentA></his:ComponentA>

甚至,这里的前缀还可以是个简称别名,比如yours=com.aaa.productA,这可能只有复杂到一定程度才会出现,大家不要以为这太夸张,但总有一天Web体系能构建超大型软件,到那时候你就知道是不是可能了。

样式的局部作用域

这个前一段时间有的浏览器实现过,在组件内部,style上加一个scoped属性,这是正确的方向。为什么要这么干呢,所谓组件,引入成本越小越好,在无约定的情况下都能引入,不造成问题,那是最佳的结果。

如果你一个组件的样式不是局部的,很可能就跟主界面的冲突了,就算你不跟主界面的冲突,怎么保证不跟主界面中包含的其他组件的样式冲突?靠命名约定是不现实的,看长远一些,等你的系统够大,这就是大问题了。

跟主文档的通讯

一个自定义组件,应当能够跟主文档进行通讯,这个过程包括两个方向,分别可以有多种不同的方式。

从内向外

除了事件,真没有什么好办法可以做这个方向的通讯,但事件也可以有两种定义方式,一种是类似onclick那种,主文档应当能够在它上面直接添加对 应的事件监听函数,就像对原生元素那样,每个事件都能单独使用。另一种是像postMessage那样,只提供一个通道,具体怎么处理,自己去定义消息格 式和处理方式。

这两种实现方式都可行,后者比较偷懒,但也够用了,前者也没有明显优势。

从外向内

这个也可以有两种方式,一种是组件对外暴露属性或者方法,让主文档调用,一种是外部也通过postMessage往里传。前者用起来会比较方便,后者也能凑合用用。

所以,如果特别偷懒,这个组件就变得像一个iframe那样,跟外部基本都通过postMessage交互。

JavaScript

写到这里我是很纠结的,因为终于来到争议最大的地方了。按照很多人的思路,我这里应该也写隔离成局部作用域的JavaScript才对,但真不行,我们可以先假设组件内部的所有JavaScript都跑在局部作用域,它不能访问主文档中的对象。

我这里解释一下之前那个坑,为什么端到端组件是有缺陷的。

先解释什么叫端到端组件。比如说,我有这么一个组件,它封装了对后端某接口的调用,还有自身的一些展示处理,跟外界通过事件通信。它整个是不需要依赖别人的,初始加载数据都是自己内部做,别人要用它也很简单,直接拿来放在页面里就可以了。

照理说,这东西应当非常好才对,使用起来这么方便,到底哪里不对?我来举个场景。

在页面上同时存在这个组件的多个实例,每个组件都去加载了初始数据,假设它们是不带参数的,每个组件加载的数据都一样,这里是不是就有浪费的请求了?有人可能觉得一点点浪费不算问题,那么继续。

假设这个组件就是一个很普通的下拉列表,用于选取人员的职业,初始可能有医生,教师,警察等等,我把这个组件直接放在界面上,它一出现,就自己去加 载了所需的列表信息并且展示了。有另外一个配置界面,用于配置这些职业信息,这时候我在里面添加了一个护士,并且提交了。假设为了数据一致性,我们把这个 变更推回到页面,麻烦就出现了。

界面只有一个职业下拉列表的时候可能还好办,有多个的时候,这个更新的策略就有问题了。

如果在组件的内部做这个推送的对接,就会出现要推送多份一致的数据给组件的不同实例的问题。如果把这个放在外面,那我们也有两种方式:

  • 订阅发布模式,组件订阅某个数据源,数据源跟服务端对接,当数据变更的时候,发给每个订阅者
  • 观察者模式,组件观察某个数据源,当数据变更的时候,去取回来

这两种很类似,不管哪种,都面临一个问题:

数据源放在哪?

很明显不能放在组件内部了,只能放在某个“全局”的地方,但刚才我们假设的是,组件内部的JavaScript代码不能访问外界的对象,所以……

但要是让它能访问,组件的隔离机制等于白搭。最好的方式,也许是两种都支持,默认是局部作用域,另外专门有一个作用域放给JS框架之类的东西用,但浏览器实现的难度可能就大了不少。

可能有人会说,你怎么把问题搞这么复杂,用这么BT的场景来给我们美好的未来出难题。我觉得问题总是要面对的,能在做出来之前就面对问题,结果应该会好一些。

我注意观察了很多朋友对Web Components的态度,大部分都是完全叫好,但其中有一部分,主要是搞前端MV*的同学对它的态度很保守,主要原因应该是我说的这几点。因为这个群体主要都在做单页型的应用,这个里面会遇到的问题是跟传统前端不同的。

那么,比如Angular,或者React,它们跟Web Components的协作点在哪里呢?我个人觉得是把引擎保留下来,上层部分逐步跟Web Components融合,所以它们不是谁吃掉谁的问题,而是怎样去融合。最终就是在前端有两层,一层是数据和业务逻辑层,一层是偏UI的,在那个层里 面,可以存在像Web Components那样的垂直切分,这样会很适宜。

最后说说自己对Polymer的意见,我的看法没有@司徒正美 那么粗暴,但我是认同他的观点的,因为Polymer的根本理念就是在做端到端组件,它会面临很多的挑战。虽然它是一个组件化框架,组件化最适宜于解决大 规模协作问题,但是如果是以走向大型单页应用这条路来看,它比Angular和React离目标的距离还远很多。

从HTML Components的衰落看Web Components的危机 HTML Components的一些特性 JavaScript什么叫端到端组件 自己对Polymer的意见的更多相关文章

  1. 力软信息化系统快速开发框架 web端+winform端

    力软信息化系统快速开发框架是一套集权限管理+快速开发+动态接口+通用组件+动态UI于一体的全新.net信息化快速开发框架.力软信息化系统快速开发框架的使用,大大地缩短了开发周期,提高了软件质量,同时也 ...

  2. iOS Web应用开发:运用HTML5、CSS3与JavaScript

    <iOS Web应用开发:运用HTML5.CSS3与JavaScript> 基本信息 原书名:Pro iOS web design and development:HTML5, CSS3, ...

  3. Lightning Web Components 来自salesforce 的web 组件化解决方案

    Lightning Web Components 是一个轻量,快速,企业级别的web 组件化解决方案,官方网站也提供了很全的文档 对于我们学习使用还是很方便的,同时我们也可以方便的学习了解salesf ...

  4. [浪风分享]App必死 Web永生 看Web的前世今生 必会卷土重来

    当我们回顾技术的演变历史时,我们也应该关注技术演变的背后逻辑. 几年前,美国的<连线>杂志发表了“Web已死,Internet永生”的文章,由于作者之一是长尾理论的提出者克里斯.安德森(C ...

  5. 从咖啡馆的经营看 Web 应用的扩展

    我经营着一家咖啡馆.经营成本同所用的资源成正比. 我的咖啡馆店面大概有一百平方英尺(约九平方米),雇佣了一个咖啡师,一台咖啡机. 营业能力: 每次能够服务一个顾客,用三分钟泡制一杯咖啡,算下来服务一个 ...

  6. 从Spring看Web项目开发

    之前简单介绍过Spring框架,本文换个角度重新诠释Spring.使用Java语言开发的项目,几乎都绕不过Spring,那么Spring到底是啥,为何被如此广泛的应用,下面从以下两个问题出发来剖析Sp ...

  7. 看Web视频整理标签笔记

    原来观看web视频,初学html的时候发现记忆不太深刻,所以自己整理了一些笔记,加深记忆且方便忘记时查看.html的规范(遵循)1.一个html文件开始标签和结束标签<html></ ...

  8. 从12306网站新验证码看Web验证码设计与破解

    2015年3月16日,铁路官方购票网站12306又出新招,在登录界面推出了全新的验证方式,用户在填写好登录名和密码之后,还要准确的选取图片验证码才能登陆成功.据悉,12306验证码改版后,目前所有抢票 ...

  9. web端,app端,小程序端测试差异详解

    前置解释:1.单纯从功能测试的层面上来讲的话,APP 测试.web 测试和H5测试在流程和功能测试上是没有区别的2.Web项目或pc项目都是在电脑上进行测试的.常见的PC项目架构有BS架构和CS架构的 ...

随机推荐

  1. JS高级 - 面向对象1(this,Object ,工厂方式,new )

    面向对象三要素: 封装 继承 多态 1.this 详解,事件处理中this的本质 window this -- 函数属于谁 <script type="text/javascript& ...

  2. hdu 1879 有的边已存在 (MST)

    Sample Input31 2 1 0 //u v w 是否已建 1 3 2 02 3 4 031 2 1 01 3 2 02 3 4 131 2 1 01 3 2 12 3 4 10 Sample ...

  3. 047 大数据下的java client连接JDBC

    1.前提 启动hiveserver2服务 url,username,password. 2.官网 3.程序 4.结果 emp的第一列与第二列 5.源程序 package com.cj.it.hiveU ...

  4. Python爬虫之PyQuery使用(六)

    Python爬虫之PyQuery使用 PyQuery简介 pyquery能够通过选择器精确定位 DOM 树中的目标并进行操作.pyquery相当于jQuery的python实现,可以用于解析HTML网 ...

  5. lintcode 最大子数组III

    题目描述 给定一个整数数组和一个整数 k,找出 k 个不重叠子数组使得它们的和最大.每个子数组的数字在数组中的位置应该是连续的. 返回最大的和. 注意事项 子数组最少包含一个数 样例 给出数组 [-1 ...

  6. AngularJS checkbox/复选框 根据缓存数据实时显示

    想缓存选择按钮时,可以使用这样的方法. index.html <!DOCTYPE html> <html data-ng-app="App"> <he ...

  7. BZOJ.4903.[CTSC2017]吉夫特(Lucas DP)

    题目链接 首先\(C(n,m)\)为奇数当且仅当\(n\&m=m\). 简要证明: 因为是\(mod\ 2\),考虑Lucas定理. 在\(mod\ 2\)的情况下\(C(n,m)\)最后只会 ...

  8. HDU.1848.Fibonacci again and again(博弈论 Nim)

    题目链接 //求三堆石子的SG函数,异或起来就是整个游戏的SG值 #include <cstdio> #include <cstring> const int N=1005; ...

  9. LOJ6041 SAM+set+树状数组

    首先对于原串建$SAM$,我们可以发先在一个点$i$的$right$集合里的点的相似度就是$len[i]$,于是可以将$SAM$的$right$集合通过$set$来启发式合并,每次加入新的点对$(i, ...

  10. centos 7 秘钥分发

    生成秘钥 [root@node1 ~]# ssh-keygen 查看秘钥 [root@node1 ~]# ls .ssh/id_rsa* .ssh/id_rsa .ssh/id_rsa.pub 将秘钥 ...