-
Notifications
You must be signed in to change notification settings - Fork 761
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
从HTML Components的衰落看Web Components的危机 #3
Comments
学习,国庆快乐。 |
如果是我来实现Web Components,很可能会以iframe为蓝本,删除作为独立页面所拥有的cookie,localStorage等东西,并且把跟主文档的关联适当删掉一些,然后,js部分真不知怎么搞了,那个公共的部分不知放哪好…… |
个人感觉Angular这样的框架主要是着重点在于MVVM的开发方式,而WC则着重于对html本身标签提供自定义的扩展方案,WC应当融入到MVVM的V层面,而VM和M层面的管理以及VM和V的双向绑定依旧交给Angular去做 |
我关于 React 跟 Web Compoennts 的对比主要基于 Pete Hunt 的说明 https://t.co/mY04yPZABR 虽然我们通常思考组件化都认为界面拆成一个个 Module, Module 之间通过事件相互通信 以及 React 所属的函数式响应式编程一派的 Elm 对于界面的处理: 说 Elm 有点跑题, 不过拿过来对比 HTML 这边, 看着确实这边的抽象有些问题..
|
|
删掉 shadow dom 代码的事情,是因为 google fork Blink 之后不再维护那部分了,Apple 的人又不想就着烂摊子继续写,所以就删了... 其实他们是想删了以后从头自己写,倒还真不是故意拆台。 |
爪机码字还痛苦。弄到后来,除了布局,都朝着 .net 里客户端组件那样的封装发展着…… |
@myst729 最新的测试版safari已经加了对shadow dom支持,开发工具已经可以展开input 内部了 |
@xufei 公共部分的疑问其实已经有解决方案,就是 SharedWorker。 |
namespace 那个我赞同。现在草案用短横线的方式是过犹不及的愚蠢方式。 |
我个人对wc持保留意见,倒不是在这些方面,而是自定义标签太容易被滥用。看看polymer的例子,大部分都是实现ui,完全违背语义化。更不要说一个custom element内部的实现(当然作为内部实现,dirty通常是无所谓的)。当初 BECSS 没有进一步标准化,至少也有因此遭到反对的部分原因。 |
求转发至 div.io ~ |
应该是“明日黄花” 哈 |
Polymer 群: 192188831 |
我X 发现issue写blog太爽了 |
发现了一个问题: 在我眼里,html/css/js 是用作排版布局的,是类似于 .doc 的东西; 可怜的html啊,能同时满足我们俩嘛... |
@ShiJinYu 这也就是我之前说,两帮不同目的的人,抢同一个平台标准的话语权,不仅仅在Web Components这块,还包括ES的语法,做应用的想一步到位搞成C#那样,做页面的只愿接受ES3-ES5这种小幅更新。 所以我一直对标准推进速度挺悲观的,觉得这两派人要的不是同样的东西。上次 @yyx990803 也说了,Web的应用化是不可逆的潮流了,从Win32,Swing,WinForm,Flex这条路线上来的我当然乐于看到这条路线,但反对者肯定越来越多…… |
我有一个奇葩的想法:把浏览器 javascript 各个模块做成类似java的package的机制,webcomponent、ES6标准全部变成一个js package集成在浏览器js引擎里,但默认不加载,代码用到时再import。 其实就是担心js变“重”,“doc”类的页面一般都要求“快”,“exe”相对这方面要求低一些。说不定随着网络和硬件的进化,这些担心都是多余的…… 还是忍不住吐槽啊,内些为了做web app而产生的奇葩DOM结构、CSS Tricks、JS Tricks实在是不忍直视啊,会被逼疯的…… |
很多时候一些技术落寞了,是受时代的局限,不能说那些技术本身不好。说不定html component的精髓会在不久的将来以另外一个形式回来。 |
组件的js本来就是全局的,你这假想一个敌人,然后来批判.... |
还是比较看好的 |
个人认为 Web Component 和 react, angular此类框架关注的问题本身就不一样 |
所以总而言之就是博主觉得 Web Component 太组件化了,和主文档的事件交流和数据交流都很麻烦,是这个意思么? |
@lizheming 经典桌面应用时代,mfc或者vcl都是mvc分离的。组件的独立性非常强。也没有见到事件交流和数据交流有多复杂。以前web的很多控件能力不强,现在这方面的劣势已经没有了。只要用桌面应用的思路能玩转,其他的领域想必是可以推广出去的。 |
@stanleyxu2005 别误解我只是看了博主的文章之后有点晕乎想要总结下文章的中心槽点,知道说什么之后才好正确判断这事... 我也没说我同意与不同意哈。 |
关于楼主提出的端到端组件第二个问题,即页面上的不同组件同步数据问题。 可能系统管理员在维护职业列表,而开单的人用一个下拉列表框读取职业列表,这个时候就是两个完全不同的上下文,没有谁会要求这时候要同步数据,就算做得到,代价太大,发生的机率太小,也没必要。 如果删除了一个职业,用户选了提交会怎样,那是业务逻辑层管控的问题,它必然会检查某个职业是否还存在资料表中。 如果用户要选取管理员刚刚新增的那个职业(那一定是它刚才有联系管理员,要求他加的),这个时候最简单的方式(程式没有负担),用户关掉程式在打开。 如果有人说用户修改了职业名称了,比如说警察修改成了护士,那用户明明看到的是警察,怎么提交后就变成了护士。这种情况确实奇葩,问题本质上是那位管理员的作法,一般会将警察修改成警察(Police),但很少会将警察变成护士这种业务上有问题的东西,因为这个table作为外键关联表,很多现在存在的数据的意义都会改变,所以还要具体场景具体分析(例如将id和名称同时带入,在服务端一起验证) 先写这些,起床了~~ |
@tsoukw 传统的企业系统确实是不需要主动同步,但我们注意到,近几年的很多系统都偏向单页化,相对注重体验了。一个单页化的应用,最重要的是变化是几乎没有“刷新”操作,所以可以看到很多这方面的探索,比如有的产品不再直接使用HTTP做通信,而是把全部业务操作都封装成某种协议,经过WebSocket进行通信。 目前来看,对于较大型的产品,业务比较复杂,做这方面的事情难度会比较高,但是如果追求极致的用户体验,这个事情是值得去探索的。 比如刚才那个职业名称列表,为什么就不能是服务端进行一个“推送”? |
2.有的时候确实要同步 这个时候涉及到的就是同步问题,首先找到导航菜单组件和快捷方式组件的共同父组件,由那个父组件(就是拼装两个组件)来实现同步。导航菜单组件在加入快捷方式成功后,发送事件给父组件,父组件调用快捷方式组件的刷新方法重新载入数据。 那还有一种是重复取数据导致的浪费问题,导航菜单组件实际上也是由多个子菜单组件组成,每个子菜单组件都要一份相同的【我的快捷方式数据】,以便在某个菜单项上显示star图标,表示这个菜单已加入快捷方式。像这样的子菜单组件,每一个都是动态载入,也不知道谁会先载入,谁会后载入,但是每个子菜单组件在自己内部都会去请求【我的快捷方式数据】,这样不仅浪费网络,也浪费内存,所以需要想办法来共用。 这种问题涉及到了组件的本质问题,到底要怎样封装一个组件? UI组件本质上只包含两个部分:view,data 其实请求逻辑是业务组件的外围,能够自己在组件内部就去完成所有数据的请求逻辑最好,但本质上它们是两个互相独立的概念。业务组件只要数据就可以完成组件渲染,数据如何来,从何处来是进一步封装的问题。默认情况下当然封装在一起,这也利于我们分而治之独立开发调试。但我们因为认识到它是外围概念,所以知道它和组件本质实际上可以分离。 在需要控制它的业务数据请求逻辑时,就可以控制(例如提供一个disableGetFavMenuData属性,如果为true,则自己不去请求),父组件停用子组件的请求后,自己去抓取相关的业务数据,并把它直接赋值给各个需要的子组件。 最近在网上看到楼主很多文章,和楼主一样,做这些事情好多年了,有空可以多多交流~~ |
@xufei 没错,如果确实要同步,就只能通过这种推送作业。 像一些面向个人的产品,如todo-list这种,在一个终端改了数据,在另一个终端如果立刻显示出来,那带给用户的体验肯定是满满幸福感的。像支付宝付钱,网页显示二维码,手机扫后,网页就知道了,马上显示付款成功。这种感觉真是太棒了,赞一个支付宝团队。 |
@tsoukw 是的,数据和组件层是需要分开设计,然后在整体方案上加以整合的。最近几年业界很多话题,有不少是跟这层东西相关的,大型应用最复杂的东西并不在上层组件的切分,而是数据和业务逻辑层的设计,以及他们与上层组件的通讯方式。 |
@xufei 大型UI,不应该是横向划分成MV*,而是应该将切成多个子组件,子组件又划分成子组件,分而治之。每个子组件可以独立运行,又可以灵活地组装,这样才有机会保证大型UI的稳定和成功。 当到最低一层的原子组件时,会发现,所有的MV_都失去了意义,直接控制view和同步数据是一件简单又高效地做法,因为view和data都足够少,MV_要解决的问题都已不再是问题。所以研究组件可能比研究MV*更应该成为UI未来的方向 |
@myst729 公司内部去dojo非常厉害 其实现在反过来看 dijit这一套东西出来得那么早 即使现在看他得一些理念还是相当厉害 就像你说的 SPA 即使用dijit也完全没问题 |
@tsoukw 组件本身也是符合mvc的.... |
但有些事情我直到后来很久以后才想明白,基于业务的端到端组件虽然写起来很方便,却是有致命缺陷的。@xufei 致命缺陷是啥啊? |
大大文章开头有个成语用错了,是明日黄花😂 |
看到评论里有提到style,最近看了一些css in js, https://vimeo.com/116209150 , https://speakerdeck.com/vjeux/react-css-in-js, 请教各位高手,对这样的技术什么态度? |
从HTML Components的衰落看Web Components的危机
搞前端时间比较长的同学都会知道一个东西,那就是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
这是一个计算器的例子,我们先大致看一下代码结构,是不是很清晰?再看看现在用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的挑战
以下逐条列出,挨个说明,有的已经有了,有的差一些,有的没有,不管这么多,总之谈谈我心目中的这个东西应当是怎样的。
自定义元素标签支持命名空间
原因我前面已经说了,可能会有不同组织实现同类功能的组件,存在于同一个页面内,引起命名歧义,所以我想了很久,还是觉得有前缀比较好:
甚至,这里的前缀还可以是个简称别名,比如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离目标的距离还远很多。
The text was updated successfully, but these errors were encountered: