WebComponent魔法堂:深究Custom Element 之 从过去看现在
前言
说起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">×</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给我惊喜的地方吧!
- htc文件内的JScript代码作用域为htc文件本身,并不污染html文件的脚本上下文;
- 带属性访问器的自定义属性大大提高我们对自定义属性的可控性;
然后就是槽点了
- htc行为与元素绑定分离,好处是灵活,缺点是非自包含,每次引入都要应用者自己绑定一次太啰嗦了。我觉得Angular通过属性E绑定元素既灵活又实现自包含才是正路啊!
- API有bug。如ondocumentready事件说好了是html文档加载完就会触发,按理只会触发一下,可实际上它总会在oncontentready事件后触发,还有fireEvent的API根本就没有,只能说继承了IE一如既往的各种坑。
- 通过runtimeStyle来设置inline style,从而会丢失继承、层叠等CSS特性的好处;
- 自定义元素内部结构会受到外部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 之 从过去看现在相关推荐
- JS魔法堂:不完全国际化本地化手册 之 拓展篇
前言 最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求--国际化&本地化.熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已. ...
- JS魔法堂:属性、特性,傻傻分不清楚
一.前言 或许你和我一样都曾经被下面的代码所困扰 var el = document.getElementById('dummy'); el.hello = "test"; con ...
- JS魔法堂:判断节点位置关系
一.前言 在polyfill querySelectorAll 和写弹出窗时都需要判断两个节点间的位置关系,通过jQuery我们可以轻松搞定,但原生JS呢?下面我将整理各种判断方法,以供日后查阅. 二 ...
- JS魔法堂:doctype我们应该了解的基础知识
一.前言 什么是doctype?其实我们一直使用,却很少停下来看清楚它到底是什么,对网页有什么作用.本篇将和大家一起探讨那个默默无闻的doctype吧! 二.什么是doctype doctype或DT ...
- CSS魔法堂:深入理解line-height和vertical-align
前言 一直听说line-height是指两行文本的基线间的距离,然后又说行高等于行距,最近还听说有个叫行间距的家伙,@张鑫旭还说line-height和vertical-align基情四射,贵圈真乱啊 ...
- JS魔法堂:那些困扰你的DOM集合类型
一.前言 大家先看看下面的js,猜猜结果会怎样吧! 可选答案: ①. 获取id属性值为id的节点元素 ②. 抛namedItem is undefined的异常 var nodes = documen ...
- CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins
前言 盒子模型作为CSS基础中的基础,曾一度以为掌握了IE和W3C标准下的块级盒子模型即可,但近日在学习行级盒子模型时发现原来当初是如此幼稚可笑.本文尝试全面叙述块级.行级盒子模型的特性.作为近日 ...
- .Net魔法堂:史上最全的ActiveX开发教程——发布篇
一. 前言 接着上一篇<.Net魔法堂:史上最全的ActiveX开发教程--开发篇>,本篇讲述如何发布我们的ActiveX. 二.废话少讲,马上看步骤! 1. 打包 C#开发的Activ ...
- CSS魔法堂:重拾Border之——图片作边框
前言 当CSS3推出border-radius属性时我们是那么欣喜若狂啊,一想到终于不用再添加额外元素来模拟圆角了,但发现border-radius还分水平半径和垂直半径,然后又发现border-t ...
最新文章
- OpenCV中响应鼠标信息cvSetMouseCallback函数的使用
- Shiro在SpringBoot中的应用
- springmvc(三) 参数绑定、
- [SDWC2018 Day1]网格
- poj 1256 Anagram—next_permutation的神奇应用
- Linux第二次作业
- 使用window.performance对应用性能监测
- 超实用的mysql分库分表策略,轻松解决亿级数据问题
- 经验分享 | 我是如何从小白到收获几个不错的offer!
- 获取Element UI中button组件的ID值
- 中国卫生健康统计年鉴(2006-2021年)
- SiamFC代码讲解,推理测试讲解
- 12款惊人的HTML5Flash视频播放器
- 如何查看XP系统的密匙
- java 二元一次方程式_JAVA求解一元一次二次方程
- 019ssm高校校园门户管理系统高校门户网站社团管理系统
- CSS3中颜色渐变色彩
- Maven项目缺少Maven Dependencies新的解决方法
- vscode中建立vue项目
- Linux——基于GPU的超低延迟远程桌面Parsec
热门文章
- Qt linux双屏,qt5 多屏显示
- image1载入大图片时如果stretch=true,image1会显示出大图片的缩图,那么如何将这个缩图镜像复制一份赋值给另一个image2的picture呢?...
- 难得一见的DIY针孔相机
- 一则 Oracle 和 SqlServer 语法区别 (原创)
- android开发那些事儿(四)--调用系统相机像素过低
- 微服务实战之Prometheus使用分享
- 关于 cocos2d-x win32 版本的 cpu 占用改良
- Unity推出2D工具:不再只是3D引擎
- 关于C++宏:AFX_EXT_CLASS
- MFC 教程【7_MFC的DLL 】