前言

 说起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 k
for (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) 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给我惊喜的地方吧!

  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

WebComponent魔法堂:深究Custom Element 之 从过去看现在的更多相关文章

  1. WebComponent魔法堂:深究Custom Element 之 标准构建

    前言  通过<WebComponent魔法堂:深究Custom Element 之 面向痛点编程>,我们明白到其实Custom Element并不是什么新东西,我们甚至可以在IE5.5上定 ...

  2. WebComponent魔法堂:深究Custom Element 之 面向痛点编程

    前言  最近加入到新项目组负责前端技术预研和选型,一直偏向于以Polymer为代表的WebComponent技术线,于是查阅各类资料想说服老大向这方面靠,最后得到的结果是:"资料99%是英语 ...

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

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

  4. CSS魔法堂:"那不是bug,是你不懂我!" by inline-block

    前言  每当来个需要既要水平排版又要设置固定高宽时,我就会想起display:inline-block,还有为了支持IE5.5/6/7的hack*display:inline;*zoom:1;.然后发 ...

  5. CSS魔法堂:小结一下Box Model与Positioning Scheme

    前言  对于Box Model和Positioning Scheme中3种定位模式的细节,已经通过以下几篇文章记录了我对其的理解和思考.  <CSS魔法堂:重新认识Box Model.IFC.B ...

  6. HTML5魔法堂:全面理解Drag & Drop API

    一.前言    在HTML4的时代,各前端工程师为了实现拖拽功能可说是煞费苦心,初听HTML5的DnD API觉得那些痛苦的日子将一去不复返,但事实又是怎样的呢?下面我们一起来看看DnD API的真面 ...

  7. CSS魔法堂:Absolute Positioning就这个样

    前言 当我们以position:absolute之名让元素脱离Normal flow的控制后,以为通过left和top属性值即可让元素得以无限的自由时,却发现还有各种神秘的力量左右着它的来去,于是我们 ...

  8. CSS魔法堂:你真的懂text-align吗?

    前言 也许提及text-align你会想起水平居中,但除了这个你对它还有多少了解呢?本篇打算和大家一起来跟text-align来一次负距离的交往,你准备好了吗? text-align属性详解 The ...

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

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

随机推荐

  1. Atitit 项目语言的选择 java c#.net  php??

    Atitit 项目语言的选择 java c#.net  php?? 1.1. 编程语言与技术,应该使用开放式的目前流行的语言趋势1 1.2. 从个人职业生涯考虑,java优先1 1.3. 从项目实际来 ...

  2. AutoMapper:Unmapped members were found. Review the types and members below. Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type

    异常处理汇总-后端系列 http://www.cnblogs.com/dunitian/p/4523006.html 应用场景:ViewModel==>Mode映射的时候出错 AutoMappe ...

  3. .NET平台开源项目速览(13)机器学习组件Accord.NET框架功能介绍

    Accord.NET Framework是在AForge.NET项目的基础上封装和进一步开发而来.因为AForge.NET更注重与一些底层和广度,而Accord.NET Framework更注重与机器 ...

  4. 对百度WebUploader开源上传控件的二次封装,精简前端代码(两句代码搞定上传)

    前言 首先声明一下,我这个是对WebUploader开源上传控件的二次封装,底层还是WebUploader实现的,只是为了更简洁的使用他而已. 下面先介绍一下WebUploader 简介: WebUp ...

  5. Java程序员:工作还是游戏,是该好好衡量一下了

    前阵子我终于下定决心,删掉了硬盘里所有的游戏. 身为一个程序猿,每天都要和各种新技术打交道,闲暇时间,总还得看一下各大论坛,逛逛博客园啥的,给自己充充电.游戏的话,其实我自小就比较喜欢,可以算是一种兴 ...

  6. 利用注册表在右键添加VS15的快捷方式打开文件夹

    1.简介 最近安装VS15 Preview 5,本版本可以打开"文件夹" 是否可以向Visual Studio Code一样在文件夹或文件右键菜单添加"Open with ...

  7. ubuntu安装ANSYS17.2全过程

    本次介绍在Ubuntu kylin1604下安装Ansys 17.2的全部过程. 1 安装文件准备 关于ANSYS的软件安装文件,在网络上可以找到.这里采用SSQ版本的安装文件,如图所示,包含一个名为 ...

  8. 在配有英特尔® Iris™ 显卡的系统上通过优化对 Just Cause 3 进行增强

    高端 PC 继续通过高性能显卡驱动桌面游戏. 一流的"梦想机器"基于第六代智能 英特尔® 酷睿™ 处理器i7-6700K等 CPU,通常与高端独立显卡配合使用以运行要求最严苛的游戏 ...

  9. POJ3693 Maximum repetition substring [后缀数组 ST表]

    Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9458   Acc ...

  10. 第13章 Linux日志管理

    1. 日志管理 (1)简介 在CentOS 6.x中日志服务己经由rsyslogd取代了原先的syslogd服务.rsyslogd日志服务更加先进,功能更多.但是不论该服务的使用,还是日志文件的格式其 ...