澳门娱乐场网址自定义标签在IE6-8的困境
自定义标签在IE6-8的困境
2015/07/20 · HTML5 · IE, 自定义标签
原文出处: 司徒正美
或许未来前端组件化之路都是自定义标签,但这东西早在20年前,JSTL已在搞了。现在Web Component还只有webkit支持。但一个组件库,还需要一个特殊的标识它们是一块的。不过这个XML已经帮我们搞定了,使用scopeName,如”<xxx:dialog>”。在我继续往下想如何处理如何为这个标签绑定数据,与其他组件通信,管理生命周期,等等大事之前,我还有一个不得不面对的问题,就是如何兼容IE6-8!
比如以下一个页面:
在chrome, firefox, IE11, IE11的IE6兼容模式分别如下:
我们会发现IE6下实际是多出许多标签,它是把闭标签也变成一个独立的元素节点
这个AA:DIV标签被开膛破肚,里面子节点全部暴出来,成为其兄弟节点了。因此想兼容它,就要费点劲。有个两个情况需要考虑,1是用户已经将它写在页面上,情况同上;2是用户是将它放在字符串模版中,这个用正则搞定。不过正则要是碰上复杂的属性名,还是会晕掉。因此我还是打算使用原生的HTML parser。换言之,字符串,我还是会将它变成节点。这么办呢?!我想了许多办法,后来还是使用VML的命名空间法搞定!
我们将上面的页面改复杂点,再看看效果!
可以看到其套嵌关系现在完全正确,并且标签名不会大写化,也不会生成多余节点!
好了,我们再判定一下是否为自定义标签,或者准确地说,这个节点是否我们组件库中定义的自定义标签。某些情况下,一个页面可以存在多套组件库,包括avalon的,ploymer的,或者是直接用Web Component写的。
avalon的组件库将使用命名空间,这样就好区别开。在IE6-9中,判定element.scopeName是否为aa(这是组件库的命名空间,你可以改个更高大上的名字),在其他浏览器判定此元素的localName是否以aa:开头就行了!
JavaScript
function isWidget(el, uiName){ return el.scopeName ? el.scopeName === uiName: el.localName.indexOf(uiName ":") === 0 }
1
2
3
|
function isWidget(el, uiName){
return el.scopeName ? el.scopeName === uiName: el.localName.indexOf(uiName ":") === 0
}
|
这个难题解决后,我们就可以开搞基于自定义标签的UI库了!
1 赞 1 收藏 评论
首先是添加和移除事件监听器,由于IE和非IE采用的方式不一样,IE采用attachEvent和detechEvent,非IE采用addEventListener和removeEventListener,而且IE只支持冒泡(从当前元素冒泡到根元素),而非IE支持冒泡和捕获(从根元素捕获到当前元素)。最开始我是这样做的:
tp.use(["tp.a","tp.b"],function(a,b) {
})
使用use方式,它会自动去下载tp.a.js和tp.b.js,下载完成之后,执行回调函数。
在没有写这个库之前,即使是我使用jquery,每一个JS文件我都是直接在HTML文件中使用script标签写进去的,而现在需要采用这种异步模块加载的方式,如果要使用非核心模块,那么需要:
我之前写了一篇日志来实现AMD,当然,效率低下,反正大家看看就行了http://my.oschina.net/mingtingling/blog/113815
现在看来,我觉得学习jquery反而使我走了弯路,用jquery是比较方便,也不用考虑兼容性问题了,而且调用非常简单优雅,但是,反而我对原生js感觉越来越陌生了,也导致了后面感觉完全离不开jquery了,想去写一个XXX组件,想了一下,思路有了,然后写的时候遇到各种问题,然后就又回到jquery了。
我看了一下,不同的库的判定方式不一样,我这儿使用的是tangram的判定方式。
好吧,貌似又超时了,先就这样吧,感觉每次写这种日志都会耗费不少时间。
这种方式我在tangram中没有看到,我是看了淘宝的KISSY之后学习到的,也就是所谓的AMD(异步模块定义)。
然后就开始下载JS的电子书,可能是自己比较浮躁吧,看书真心看不进去,我还是喜欢边看边写代码这种。写了一段时间,渐渐的觉得最开始的感觉慢慢回来了,当然,也遇到了N多的问题。
然后就是浏览器判定,我是这么写的:
tp.use("tp.dom.sizzle",function(sizzle) {});
我这儿写了一个openClassScan参数,解释一下,这个参数是为了解决类似于<div class = "a b"></div>这种,因为如果要支持通过API查询如class:a,那么需要每个节点都判定是否contain这个class,比较费时间,而我认为很多时候不需要,所以默认我关闭了。
还记得我大二的时候开始接触JS,那个时候从图书馆借了N多的书籍,然后边看边用editplus写,然后遇到问题,各种DEBUG,在做项目的时候,各种兼容性问题,真是痛苦啊。由于项目需要尽快写完,所以就开始接触了jquery,还是从图书馆抱了几本书,然后下载了jquery源码,然后边看书籍边写代码,看了几章之后,觉得貌似不难,然后就从网上下载了jquery的文档,对照着文档,对其调用搞得算是比较清楚了。
我把每一个查询如:tp.dom.query("#aa input")分为两种,一种为简单查询(也就是如查询:#aaa),另外一种是复杂查询,每个复杂查询都是由很多简单查询构成的,比如#aaa input,就可以切成:#aaa和input。
PS:使用了原生的document.getElementsByClassName的肯定不受这个影响的。
注意一下啊,由于JS变量作用域没有block,所以请不要使用下面这种:
我认为:#aa input这种实际上就是通过document.getElementById查询之后然后查询它的子孙节点中的所有满足tagName为input的元素;而#aaa > input这种就是查询它的孩子节点中是否有这种满足条件的元素。现在整个流程比较简单了,对于一个复杂查询,首先进行一个简单查询,然后按照查询的结果集合,进行一次遍历,对每个节点查询它的孩子节点或子孙节点,将所有满足条件的放入到另外一个数组,如果该数组为空,那么直接返回空数组,否则,继续进行下一次查询(依旧查询孩子节点或子孙节点)。
澳门娱乐场网址, #aa这种比较简单,因为JS提供了API,也就是document.getElementById;input这种也比较好搞,因为JS有document.getElementsByTagName;但是.aa这种方式就比较纠结了,因为JS没有提供API,幸好,在一些浏览器中还是提供了API:document.getElementsByClassName,而那些没有提供这个API的就比较悲剧了,只能遍历所有节点,也就是使用document.getElementsByTagName(*):
tp.event.preventDefault = function(event) {
if(event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
};
tp.event.stopPropagation = function(event) {
if(event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
};
除了DOM,对变量类型的判定和浏览器的检测也是很重要的。
tp.event.on = function(element,event,fn) {
_addEventListener(element,event,fn,false);
};
tp.event.getTarget = function(event) {
return event.target || event.srcElement;
};
开始写的感觉真是痛苦啊,什么都不懂,所以就去看了看tangram的源码,为什么看tangram呢,其实原因比较搞笑,当时校招的时候我面试百度前端,被刷掉了,当时面试官让我看看它们百度使用的JS库tangram,我就想看看它们那个库到底有什么了不起的。。。
(function() {
var ua = navigator.userAgent;
tp.browser.isIe = ua.hasString("MSIE") && !ua.hasString("Opera");
tp.browser.isFirefox = ua.hasString("Firefox");
tp.browser.isChrome = ua.hasString("Chrome");
tp.browser.isWebKit = ua.hasString("WebKit");
tp.browser.isGecko = ua.hasString("Gecko") && !ua.hasString("like Gecko");
tp.browser.isOpera = ua.hasString("Opera");
tp.browser.isSafari = ua.hasString("Safari") && !ua.hasString('Chrome');
tp.browser.isStrict = ("CSS1Compat" === document.compatMode);
})();
在使用事件代理的时候,我们经常要获取到事件的目标元素,而IE和非IE又是不一样的,所以需要单独写一个函数:
首先是ready的判定,关于这个可以看我另外一篇日志:http://my.oschina.net/mingtingling/blog/110282
var _getElementsByClassName = null;
if(document.getElementsByClassName) {
_getElementsByClassName = function(str) {
var fetchedEles = document.getElementsByClassName(str),
eles = [];
for(var i = 0, len = fetchedEles.length; i < len; i ) {
eles.push(fetchedEles[i]);
}
return eles;
};
} else {
_getElementsByClassName = function(str,openClassScan) {
var eles = [],
allElements = document.getElementsByTagName("*"),
i;
if(openClassScan) {
for (i = 0; i< allElements.length; i ) {
if (tp.dom.containClass(allElements[i],str)) {
eles.push(allElements[i]);
}
}
} else {
for (i = 0; i< allElements.length; i ) {
if (str === allElements[i].className) {
eles.push(allElements[i]);
}
}
}
return eles;
};
}
我这儿写了一个辅助函数:
之后写一个辅助函数,判定是否是复杂查询,如果是,那么切开查询字符串,切成数组。
var _listeners = {},
_addEventListener,
_removeEventListener;
if (window.attachEvent) {
var _realEventCallbackFns = {};
_addEventListener = function(element,event,fn) {
//第三个参数_realFn是为了修正this
var realFn = function(e) {fn.call(element,e);};
_realEventCallbackFns[fn] = realFn;
element.attachEvent("on" event,realFn);
};
_removeEventListener = function(element,event,fn) {
element.detachEvent("on" event,_realEventCallbackFns[fn]);
};
} else if (window.addEventListener) {
_addEventListener = function(element,event,fn,capture) {
element.addEventListener(event, fn,capture);
};
_removeEventListener = function (element,event,fn,capture) {
element.removeEventListener(event,fn,capture);
};
} else {
_addEventListener = function(element,event,fn) {
element["on" event] = fn;
};
_removeEventListener = function(element,event) {
delete element["on" event];
};
}
tp.event.on = function(element,event,fn) {
if (window.attachEvent) {
//IE
//第三个参数_realFn是为了修正this
var realFn = function(e{fn.call(element,e);};
_realEventCallbackFns[fn] = realFn;
element.attachEvent("on" event,realFn);
} else if (window.addEventListener) {
element.addEventListener(event, fn,false);
} else {
element["on" event] = fn;
}
};
对动画有兴趣的童鞋,可以看看我的最近学习JS的感悟-2,关于动画的http://my.oschina.net/mingtingling/blog/127296。
本文由澳门娱乐场网址发布于计算机教程,转载请注明出处:澳门娱乐场网址自定义标签在IE6-8的困境
关键词:
上一篇:使用Fiddler搭建手机调试环境(我做得项目是调试
下一篇:没有了