最近学习JS的感悟美高梅娱乐场网站-1

发布时间:2019-02-13  栏目:计算机教程  评论:0 Comments

自定义标签在IE6-8的困境

2015/07/20 · HTML5 ·
IE,
自定义标签

原文出处:
司徒正美   

或许未来前端组件化之路都是自定义标签,但这东西早在20年前,JSTL已在搞了。现在Web
Component还只有webkit支持。但一个组件库,还需要一个特殊的标识它们是一块的。不过这个XML已经帮我们搞定了,使用scopeName,如”<xxx:dialog>”。在我继续往下想如何处理如何为这个标签绑定数据,与其他组件通信,管理生命周期,等等大事之前,我还有一个不得不面对的问题,就是如何兼容IE6-8!

比如以下一个页面:

美高梅娱乐场网站 1

在chrome, firefox, IE11, IE11的IE6兼容模式分别如下:

美高梅娱乐场网站 2
美高梅娱乐场网站 3
美高梅娱乐场网站 4
美高梅娱乐场网站 5

我们会发现IE6下实际是多出许多标签,它是把闭标签也变成一个独立的元素节点

美高梅娱乐场网站 6

这个AA:DIV标签被开膛破肚,里面子节点全部暴出来,成为其兄弟节点了。因此想兼容它,就要费点劲。有个两个情况需要考虑,1是用户已经将它写在页面上,情况同上;2是用户是将它放在字符串模版中,这个用正则搞定。不过正则要是碰上复杂的属性名,还是会晕掉。因此我还是打算使用原生的HTML
parser。换言之,字符串,我还是会将它变成节点。这么办呢?!我想了许多办法,后来还是使用VML的命名空间法搞定!

我们将上面的页面改复杂点,再看看效果!

美高梅娱乐场网站 7
美高梅娱乐场网站 8

可以看到其套嵌关系现在完全正确,并且标签名不会大写化,也不会生成多余节点!

好了,我们再判定一下是否为自定义标签,或者准确地说,这个节点是否我们组件库中定义的自定义标签。某些情况下,一个页面可以存在多套组件库,包括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 收藏
评论

美高梅娱乐场网站 9

        然后就是浏览器判定,我是这么写的:

     
暂时AMD的实现方式是通过setInterval,但是即将被重构美高梅娱乐场网站 10

         
在使用事件代理的时候,我们经常要获取到事件的目标元素,而IE和非IE又是不一样的,所以需要单独写一个函数:

          我这儿写了一个辅助函数:

         
感觉JS的兼容性真心很头疼啊,就比如在DOM这一块儿,为了兼容,我都做了很长时间。当然,DOM这一块儿肯定不止这么一点内容,暂时也不写了。

       
 这里我主要讲一下tp.dom.query,也就是查询怎么做的,首先看看常用的查询有:#aa,.aa,input。

           所以,在每个查询的最开始,需要将传递的查询格式化,比如#aa
>input这种格式化为:#aa >
input,多个空格变为1个空格,>两边必须有一个空格等。

      同样,在tp.a.js中,也不能使用普通的JS的写法了,而要使用:

  

     
 除了代码之外,工具也很重要,另一篇日志介绍JS工具的:http://my.oschina.net/mingtingling/blog/113295

       
开始写的感觉真是痛苦啊,什么都不懂,所以就去看了看tangram的源码,为什么看tangram呢,其实原因比较搞笑,当时校招的时候我面试百度前端,被刷掉了,当时面试官让我看看它们百度使用的JS库tangram,我就想看看它们那个库到底有什么了不起的。。。

美高梅娱乐场网站,       
 首先是ready的判定,关于这个可以看我另外一篇日志:http://my.oschina.net/mingtingling/blog/110282

   
 也就是在一个函数内部去判定是否是IE,然后相应的执行相应的函数,但是这样,如果添加的事件监听器很多,每次都if什么的,我个人感觉很不好,所以我后面添加了一个辅助函数:

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库,反而自己来写一个不完善的库,这样学习的更多,当然,也比较费时间。

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];
        };
    }

         
 除了事件监听器,还需要事件事件的添加,删除等,也就是add,fire,remove等,这里就不说了。

          除了DOM,对变量类型的判定和浏览器的检测也是很重要的。

     
 除了这种判定方式,还可以通过判定是否有某一个函数或某一个变量来判定,这种判定方式我忘记叫什么名字了,反正之前这种叫浏览器嗅探。

       
现在看来,我觉得学习jquery反而使我走了弯路,用jquery是比较方便,也不用考虑兼容性问题了,而且调用非常简单优雅,但是,反而我对原生js感觉越来越陌生了,也导致了后面感觉完全离不开jquery了,想去写一个XXX组件,想了一下,思路有了,然后写的时候遇到各种问题,然后就又回到jquery了。

var tp = tp || {};
tp.use("tp.dom.sizzle",function(sizzle) {});
var arr = new Array(),
    i;

         
常用的功能当然还是阻止事件冒泡以及阻止默认事件的发生,很遗憾,IE和非IE处理方式还是不一样的,比如阻止冒泡IE采用的是cancelBubble,而其他浏览器采用的是stopPropagation,所以还是需要写:

     
使用use方式,它会自动去下载tp.a.js和tp.b.js,下载完成之后,执行回调函数。

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;
        }
    };
define("tp.a",["tp.c","tp.d"],function(c,d) {
   tp.modules.add("tp.a",function() {

    });
});

      这样使用变量i已经被重复定义了,所以需要把变量i定义在if之前,即:

     
 由于这个库完全是为毕设做的,所以这里面的很多文件都是为实现毕设的某些功能而写的。

           那这样,tp.event.on就变得非常简单了:

       
 事件这一块儿实际上我做了N多东西,但是由于讲不完,所以暂时不说了。

         
 之后写一个辅助函数,判定是否是复杂查询,如果是,那么切开查询字符串,切成数组。

   
 define的第一个参数是该组件的名字(需要唯一,所以我还是按照命名空间的方式写的),第二个参数是这个组件所依赖的组件,第三个参数是回调函数,也就是当依赖的组件下载完成之后,回调执行,而tp.modules.add就可以将这个模块加载到整个库中,这样的话才能使用tp.use调用。

         
 这样,整个判定只需要执行一次,后面调用的时候只需要使用_addEventListener即可,当然,由于采用了闭包,tp.event命名空间之外是不可访问这几个函数的。

留下评论

网站地图xml地图