WebComponent魔法堂:深究Custom Element 之 从过去看现在
说起Custom Element那必然会想起那个相似而又以失败告终的HTML Component。HTML Component是在IE5开始引入的新技术,用于对原生元素作功能"增强",虽然仅仅被IE所支持,虽然IE10也开始放弃它了,虽然掌握了也用不上,但还是不影响我们以研究的心态去了解它的:)
把玩HTML ComponentHTML 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.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 k for (k in ctx){ tpl = tpl.replace(RegExp(\$\{ + k + \}), ctx[k] return tpl // 元素内部结构 var tpl = div \ button type="button" aria-label="Close" \ span aria-hidden="true" times; /span \ /button \ div ${raw} /div \ /div var getHtml = curry(compile, tpl) * leftcycle region var inited = 0, oHtml = function onattach(){ if (inited) return oHtml = element.innerHTML var ctx = { raw: heading + oHtml var html = genHtml(ctx) element.innerHTML = html runtimeStyle.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行为与元素绑定分离,好处是灵活,缺点是非自包含,每次引入都要应用者自己绑定一次太啰嗦了。我觉得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
通过《WebComponent魔法堂:深究Custom Element 之 面向痛点编程》,我们明白到其实Custom Element并不是什么新东西,我们甚至可以在IE5.5上定义自己的alert元素。
【基础】Attribute的妙用 如果您觉得文章对您有帮助,可以【打赏】博主或点击文章右下角【推荐】一下。您的鼓励是博主坚持原创和持续写作的最大动力!
相关文章
- Vue element-ui 限制时间范围选择
- [CSS3] Hide some DOM element while print
- vue.js3:element-plus使用例子:用滑块调节图片灰度(element-plus@2.2.2 / vue@3.2.36)
- 使用Chrome的inspect element注意事项
- element中el-cascader级联获取name和id值(整理)
- Vue中使用element-ui的el-dialog对话框,实现拖拽效果(整理)
- element查看大图添加下载按钮(整理)
- 【异常】Maven提示 repository element was not specified in the POM inside distributionManagement element
- The content of element type "resultMap" must match "(constructor?,id*,result*,association*,collection*,discriminator?)".
- 页面使用element-tree