前言

 说起Custom Element那必然会想起那个相似而又以失败告终的HTML Component。HTML Component是在IE5开始引入的新技术,用于对原生元素作功能"增强",虽然仅仅被IE所支持,虽然IE10也开始放弃它了,虽然掌握了也用不上,但还是不影响我们以研究的心态去了解它的:)

把玩HTML Component

 HTML Component简称HTC,它由定义和应用两部分组成。定义部分写在.htc文件中(MIME为text/x-component),由HTC独有标签、JScript和全局对象(element,window等)组成;而应用部分则写在html文件中,通过CSS的behavior规则附加到特定的元素上。

定义部分

HTC独有标签
PUBLIC:COMPONENT, 根节点.
PUBLIC:PROPERTY, 定义元素公开自定义属性/特性.
 属性
NAME,html文件中使用的属性名
INTERNALNAME,htc文件内使用的属性名,默认与NAME一致
VALUE,属性默认值
PUT,setter对应的函数名
GET,getter对应的函数名
PUBLIC:EVENT, 定义元素公开自定义事件.
 属性
NAME,公开事件名称,如onheadingchange
ID,htc内使用的事件名称,如ohc.然后通过ohc.fire(createEventObject())来触发事件
PUBLIC:ATTACH,订阅事件
 属性
EVENT,订阅的事件名称,如onheadingchange
ONEVENT,事件处理函数体,如headingchangehandler()
FOR,事件发生的宿主(element,document,window,默认是element)
PUBLIC:METHOD, 定义元素公开方法
 属性
NAME,html文件中使用的方法名
INTERNALNAME,htc文件内使用的方法名,默认与NAME一致。在JScript中实现具体的方法体
PUBLIC:DEFAULTS,设置HTC默认配置
HTC生命周期事件
ondocumentready, 添加到DOM tree时触发,在oncontentready后触发
oncontentready, 添加到DOM tree时触发
ondetach, 脱离DOM tree时触发, 刷新页面时也会触发
oncontentsave, 当复制(ctrl-c)element内容时触发
HTC全局对象
element, 所附加到的元素实例
runtimeStyle,所附加到的元素实例的style属性
document,html的文档对象
HTC全局函数
createEventObject(),创建事件对象
attachEvent(evtName, handler), 订阅事件.注意:一般不建议使用attachEvent来订阅事件,采用<PUBLIC:ATTACH>来订阅事件,它会自动帮我们执行detach操作,避免内存泄露.
detachEvent(evtName[, handler]), 取消订阅事件

应用部分

引入.htc
1.基本打开方式

<style>css-selector{behavior: url(file.htc);}
</style>

2.打开多个

<style>css-selector{behavior: url(file1.htc) url(file2.htc);}
</style>

 可以看到是通过css-selector匹配元素然后将htc附加到元素上,感觉是不是跟AngularJS通过属性E指定附加元素的方式差不多呢!
3.自定义元素

<html xmlns:x><head><style>x\:alert{behavior: url(x-alert.htc);}</style></head><body><x:alert></x:alert></body>
</html>

 自定义元素则有些麻烦,就是要为自定义元素指定命名空间x:alert,然后在html节点上列出命名空间xmlns:x。(可多个命名空间并存<html xmlns:x xmlns:y>)
 下面我们来尝试定义一个x:alert元素来看看具体怎么玩吧!

自定义x:alert元素

x-alert.htc

<PUBLIC:COMPONENT><PUBLIC:ATTACH EVENT="oncontentready" ONEVENT="onattach()"></PUBLIC:ATTACH><PUBLIC:ATTACH EVENT="ondetach" ONEVENT="ondetach()"></PUBLIC:ATTACH><PUBLIC:METHOD NAME="close"></PUBLIC:METHOD><PUBLIC:METHOD NAME="show"></PUBLIC:METHOD><PUBLIC:PROPERTY NAME="heading" PUT="putHeading" SET="setHeading"></PUBLIC:PROPERTY><PUBLIC:EVENT NAME="onheadingchange" ID="ohc"></PUBLIC:EVENT><PUBLIC:ATTACH EVENT="onclick" ONEVENT="onclick()"></PUBLIC:ATTACH><script language="JScript">/* * private region*/function toArray(arrayLike, sIdx, eIdx){return Array.prototype.slice.call(arrayLike, sIdx || 0, eIdx || arrayLike.length)}function curry(fn /*, ...args*/){var len = fn.length, args = toArray(arguments, 1)return len <= args.length ? fn.apply(null, args.slice(0, len)) : function next(args){return function(){var tmpArgs = args.concat(toArray(arguments))return len <= tmpArgs.length ? fn.apply(null, tmpArgs.slice(0, len)) : next(tmpArgs)}}(args)}function compile(tpl, ctx){var kfor (k in ctx){tpl = tpl.replace(RegExp('\$\{' + k + '\}'), ctx[k]}return tpl}// 元素内部结构var tpl = '<div class="alert alert-warning alert-dismissible fade in">\<button type="button" class="close" aria-label="Close">\<span aria-hidden="true">&times;</span>\</button>\<div class="content">${raw}</div>\</div>'var getHtml = curry(compile, tpl)/* * leftcycle region*/var inited = 0, oHtml = ''function onattach(){if (inited) returnoHtml = element.innerHTMLvar ctx = {raw: heading + oHtml}var html = genHtml(ctx)element.innerHTML = htmlruntimeStyle.display = 'block'runtimeStyle.border = 'solid 1px red'}function ondetach(){}/* * public method region*/function show(){runtimeStyle.display = 'block'}function close(){runtimeStyle.display = 'none'}/** public property region*/var heading = ''function putHeading(val){if (heading !== val){setTimeout(function(){var evt = createEventObject()evt.propertyName = 'heading'ohc.fire(evt)}, 0)}heading = val}function getHeading(){return heading}/** attach event region*/function onclick(){if (/^\s*close\s*$/.test(event.srcElement.className)){close()}}</script>
</PUBLIC:COMPONENT>

引用x:alert

index.html

<html xmlns:x>
<head><title></title><style>x\:alert{behavior: url(x-alert.htc);}</style>
</head>
<body><x:alert id="a" heading="Hello world!"></x:alert>    <script language="JScript">var a = document.getElementById('a')a.onheadingchange = function(){alert(event.propertyName + ':' + a.heading)} // a.show()// a.close()// document.body.appendChilid(document.createElement('x:alert'))</script>
</body>
</html>

感受

 在写HTC时我有种写C的感觉,先通过HTC独有标签声明事件、属性、方法等,然后通过JScript来提供具体实现,其实写Angular2时也有这样的感觉,不过这里的感觉更强烈一些。
这里先列出开发时HTC给我惊喜的地方吧!

  1. htc文件内的JScript代码作用域为htc文件本身,并不污染html文件的脚本上下文;
  2. 带属性访问器的自定义属性大大提高我们对自定义属性的可控性;

然后就是槽点了

  1. htc行为与元素绑定分离,好处是灵活,缺点是非自包含,每次引入都要应用者自己绑定一次太啰嗦了。我觉得Angular通过属性E绑定元素既灵活又实现自包含才是正路啊!
  2. API有bug。如ondocumentready事件说好了是html文档加载完就会触发,按理只会触发一下,可实际上它总会在oncontentready事件后触发,还有fireEvent的API根本就没有,只能说继承了IE一如既往的各种坑。
  3. 通过runtimeStyle来设置inline style,从而会丢失继承、层叠等CSS特性的好处;
  4. 自定义元素内部结构会受到外部JS、CSS的影响,并不是一个真正闭合的元素。

总结

 很抱歉本文的内容十分对不住标题所述,更全面的观点请查看徐飞老师的《从HTML Components的衰落看Web Components的危机》。假如单独看Custom Element,其实它跟HTML Component无异,都没有完整的解决自定义元素/组件的问题,但WebComponent除了Custom Element,还有另外3个好伙伴(Shadow DOM,template,html imports)来一起为自定义元素提供完整的解决方案,其中Shadow DOM可谓是重中之重,后续继续研究研究:)
 尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/5987853.html ^_^肥仔John

感谢

《从HTML Components的衰落看Web Components的危机》
HTC Reference
Using HTML Components to Implement DHTML Behaviors in Script

转载于:https://www.cnblogs.com/fsjohnhuang/p/5987853.html

WebComponent魔法堂:深究Custom Element 之 从过去看现在相关推荐

  1. JS魔法堂:不完全国际化本地化手册 之 拓展篇

    前言  最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求--国际化&本地化.熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已. ...

  2. JS魔法堂:属性、特性,傻傻分不清楚

    一.前言 或许你和我一样都曾经被下面的代码所困扰 var el = document.getElementById('dummy'); el.hello = "test"; con ...

  3. JS魔法堂:判断节点位置关系

    一.前言 在polyfill querySelectorAll 和写弹出窗时都需要判断两个节点间的位置关系,通过jQuery我们可以轻松搞定,但原生JS呢?下面我将整理各种判断方法,以供日后查阅. 二 ...

  4. JS魔法堂:doctype我们应该了解的基础知识

    一.前言 什么是doctype?其实我们一直使用,却很少停下来看清楚它到底是什么,对网页有什么作用.本篇将和大家一起探讨那个默默无闻的doctype吧! 二.什么是doctype doctype或DT ...

  5. CSS魔法堂:深入理解line-height和vertical-align

    前言 一直听说line-height是指两行文本的基线间的距离,然后又说行高等于行距,最近还听说有个叫行间距的家伙,@张鑫旭还说line-height和vertical-align基情四射,贵圈真乱啊 ...

  6. JS魔法堂:那些困扰你的DOM集合类型

    一.前言 大家先看看下面的js,猜猜结果会怎样吧! 可选答案: ①. 获取id属性值为id的节点元素 ②. 抛namedItem is undefined的异常 var nodes = documen ...

  7. CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins

    前言   盒子模型作为CSS基础中的基础,曾一度以为掌握了IE和W3C标准下的块级盒子模型即可,但近日在学习行级盒子模型时发现原来当初是如此幼稚可笑.本文尝试全面叙述块级.行级盒子模型的特性.作为近日 ...

  8. .Net魔法堂:史上最全的ActiveX开发教程——发布篇

    一. 前言 接着上一篇<.Net魔法堂:史上最全的ActiveX开发教程--开发篇>,本篇讲述如何发布我们的ActiveX. 二.废话少讲,马上看步骤! 1. 打包  C#开发的Activ ...

  9. CSS魔法堂:重拾Border之——图片作边框

    前言  当CSS3推出border-radius属性时我们是那么欣喜若狂啊,一想到终于不用再添加额外元素来模拟圆角了,但发现border-radius还分水平半径和垂直半径,然后又发现border-t ...

最新文章

  1. OpenCV中响应鼠标信息cvSetMouseCallback函数的使用
  2. Shiro在SpringBoot中的应用
  3. springmvc(三) 参数绑定、
  4. [SDWC2018 Day1]网格
  5. poj 1256 Anagram—next_permutation的神奇应用
  6. Linux第二次作业
  7. 使用window.performance对应用性能监测
  8. 超实用的mysql分库分表策略,轻松解决亿级数据问题
  9. 经验分享 | 我是如何从小白到收获几个不错的offer!
  10. 获取Element UI中button组件的ID值
  11. 中国卫生健康统计年鉴(2006-2021年)
  12. SiamFC代码讲解,推理测试讲解
  13. 12款惊人的HTML5Flash视频播放器
  14. 如何查看XP系统的密匙
  15. java 二元一次方程式_JAVA求解一元一次二次方程
  16. 019ssm高校校园门户管理系统高校门户网站社团管理系统
  17. CSS3中颜色渐变色彩
  18. Maven项目缺少Maven Dependencies新的解决方法
  19. vscode中建立vue项目
  20. Linux——基于GPU的超低延迟远程桌面Parsec

热门文章

  1. Qt linux双屏,qt5 多屏显示
  2. image1载入大图片时如果stretch=true,image1会显示出大图片的缩图,那么如何将这个缩图镜像复制一份赋值给另一个image2的picture呢?...
  3. 难得一见的DIY针孔相机
  4. 一则 Oracle 和 SqlServer 语法区别 (原创)
  5. android开发那些事儿(四)--调用系统相机像素过低
  6. 微服务实战之Prometheus使用分享
  7. 关于 cocos2d-x win32 版本的 cpu 占用改良
  8. Unity推出2D工具:不再只是3D引擎
  9. 关于C++宏:AFX_EXT_CLASS
  10. MFC 教程【7_MFC的DLL 】