塞班岛贵宾会最近学习JS的感悟-1

自定义标签在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

     
 还记得作者大二的时候开端接触JS,那时从体育场面借了N多的书本,然后面看边用editplus写,然后际遇难点,各类DEBUG,在做项指标时候,各类包容性难点,真是难过啊。由于项目供给尽快写完,所以就从头接触了jquery,照旧从体育场合抱了几本书,然后下载了jquery源码,然前边看书籍边写代码,看了几章之后,以为貌似轻便,然后就从英特网下载了jquery的文书档案,对照着文书档案,对其调用搞拿到底相比清楚了。

       
今后总来讲之,小编以为学习jquery反而使自身走了弯路,用jquery是相比有利,也休想思量包容性难点了,况且调用非常轻松文雅,不过,反而作者对原生js感到越是不熟悉了,也促成了前边以为完全离不开jquery了,想去写一个XXX组件,想了刹那间,思路有了,然后写的时候遭受种种问题,然后就又回来jquery了。

       
 从那意气风发季度暑假的时候,小编主宰离开jquery了,jquery是生机勃勃把双刃剑,开辟的时候是便于,不过,作为三个初大家,笔者觉着那是非常不利的。

       
 然后就从头下载JS的E-BOOK,或许是自个儿比较急躁吧,看书真心看不进来,小编还是喜欢边看边写代码这种。写了后生可畏段时间,慢慢的感觉最发轫的觉获得稳步回来了,当然,也遇上了N多的标题。

       
到寒假的时候,决定本人的毕设不行使以往成熟的JS库,反而本身来写叁个不周全的库,那样学习的更加多,当然,也比较费时间。

       
开头写的感觉到真是哀痛啊,什么都不懂,所以就去看了看tangram的源码,为何看tangram呢,其实原因相比好笑,那时候校招的时候笔者面试百度前端,被刷掉了,那时候面试官让本身看看它们百度行使的JS库tangram,作者就想看看它们特别库到底有怎么着了不起的。。。

       
写那么些库,首先选拔了命名空间,笔者比较喜欢toper,所以自个儿首先定义了三个变量:

var tp = tp || {};

       
这种办法也是以古为鉴了tangram的写法,选拔对象字面量的花样。那样全部toper定义的章程都放在了tp那么些私有空间内了,举个例子对DOM的操作就位于tp.dom中。

     
 由于这几个库完全部是为毕设做的,所以那中间的众多文本都感到达成毕设的一些意义而写的。

     
笔者利用的布局是core+组件的艺术,tp.core.js(压缩后为tp.core-min.js卡塔 尔(阿拉伯语:قطر‎,而别的的零构件每种组件二个文件,而组件之间大概存在依据关系,这种依据关系就由此英特尔解决。

     
在平昔不写那么些库此前,纵然是自家动用jquery,每一个JS文件作者都以直接在HTML文件中利用script标签写进去的,而前天急需利用这种异步模块加载的艺术,借使要选择非大旨模块,那么要求:

tp.use(["tp.a","tp.b"],function(a,b) {

})

     
使用use情势,它会活动去下载tp.a.js和tp.b.js,下载完成以往,实践回调函数。

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

 

define("tp.a",["tp.c","tp.d"],function(c,d) {
   tp.modules.add("tp.a",function() {

    });
});

   
 define的首先个参数是该构件的名字(要求唯大器晚成,所以笔者要么固守命名空间的秘籍写的卡塔 尔(阿拉伯语:قطر‎,第二个参数是那一个组件所信任的机件,第3个参数是回调函数,也正是当注重的零部件下载完毕之后,回调实践,而tp.modules.add就能够将那几个模块加载到整个库中,那样的话才具使用tp.use调用。

     
这种措施本人在tangram中绝非看出,小编是看了Taobao的KISSY之后求学到的,也便是所谓的英特尔(异步模块定义卡塔尔。

     
近来速龙的落真实景况势是通过setInterval,可是就要被重构塞班岛贵宾会 10

     
作者前边写了风流浪漫篇日记来落实英特尔,当然,功能低下,反正大家看看就行了

     
然后便是事件了,事件是叁个相比恼火的业务,东西超级多,小编把它坐落了tp.event那些空间中。

     
首先是丰硕和移除事件监听器,由于IE和非IE选拔的艺术分化样,IE采取attach伊芙nt和detechEvent,非IE接收add伊夫ntListener和removeEventListener,并且IE只补助冒泡(从脚下因素冒泡到根元素卡塔 尔(英语:State of Qatar),而非IE辅助冒泡和破获(从根成分捕获到日前成分卡塔 尔(英语:State of Qatar)。最起头自身是如此做的:

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

   
 也正是在叁个函数内部去看清是不是是IE,然后相应的实行相应的函数,可是如此,借使加上的平地风波监听器相当多,每一遍都if什么的,作者个人认为很倒霉,所以自个儿前面增添了一个帮助函数:

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

         
 这样,整个推断只要求执行一遍,前边调用的时候只供给动用_addEventListener即可,当然,由于接受了闭包,tp.event命名空间之外是不足访谈那多少个函数的。

           那那样,tp.event.on就变得非常轻松了:

tp.event.on = function(element,event,fn) {
        _addEventListener(element,event,fn,false);
         };

         
并且这么还应该有八个益处,此前的不二等秘书籍只好利用冒泡形式,但今后,能够行使捕获,当然,只可以非IE本领接纳,那样在背后使用事件代理一些非冒泡的事件的时候非常有用,比方blur和focus事件。

         
 除了事件监听器,还亟需事件风浪的丰硕,删除等,也便是add,fire,remove等,这里就背着了。

         
在利用事件代理的时候,大家日常要博得到事件的对象成分,而IE和非IE又是不等同的,所以必要独自写一个函数:

tp.event.getTarget = function(event) {
        return event.target || event.srcElement;
    };

         
常用的效能自然照旧阻止事件冒泡以致阻碍暗中同意事件的发出,很可惜,IE和非IE处理情势照旧不等同的,举个例子阻止冒泡IE选择的是cancelBubble,而其他浏览器接受的是stopPropagation,所以依然须求写:

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

       
 事件这一同实际笔者做了N多东西,不过由于讲不完,所以不时不说了。

        注意一下啊,由于JS变量效能域未有block,所以请不要接受下边这种:

var arr = new Array();
if(xxx) {
   for(var i = 0,len = arr.length ; i < len; i++) {

   }
} else {
   for(var i = 0,len = arr.length ; i < len; i++) {

   }
}

      那样使用变量i已经被重新定义了,所以必要把变量i定义在if以前,即:

var arr = new Array(),
    i;

          事件之后,当然便是DOM了,感到各样库在此个地点都做了成都百货上千办事。

       
 首先是ready的论断,关于这一个可以看本人其余生龙活虎篇日记:

       
 这里作者第黄金年代讲一下tp.dom.query,也等于查询怎么办的,首先造访常用的询问有:#aa,.aa,input。

       
 #aa这种比较简单,因为JS提供了API,也正是document.getElementById;input这种也比较好搞,因为JS有document.getElementsByTagName;不过.aa这种办法就对比郁结了,因为JS未有提供API,幸亏,在部分浏览器中可能提供了API:document.getElementsByClassName,而那多少个从没提供那一个API的就相比较正剧了,只可以遍历全数节点,也等于应用document.getElementsByTagName(*):

          作者那时候写了一个增派函数:

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

           
笔者那儿写了贰个openClassScan参数,解释一下,这么些参数是为着减轻相通于<div
class = “a
b”></div>这种,因为生机勃勃旦要援助通过API查询如class:a,那么须求种种节点都认清是还是不是contain这几个class,相比费时间,而自身感到超多时候不要求,所以暗中同意本人关闭了。

           
PS:使用了原生的document.getElementsByClassName的任其自然不受那么些影响的。

           我把每三个查询如:tp.dom.query(“#aa
input”)分为三种,风姿浪漫种为简易询问(也正是如查询:#aaa卡塔尔国,别的大器晚成种是头晕目眩查询,种种复杂查询都以由大多精练询问构成的,举例#aaa
input,就足以切成:#aaa和input。

           所以,在各种查询的最起初,需求将传递的询问格式化,比方#aa
>input这种格式化为:#aa >
input,八个空格变为1个空格,>两侧必得有贰个空格等。

         
 之后写一个救助函数,剖断是不是是复杂查询,假如是,那么切开查询字符串,切成数组。

           我认为:#aa
input这种实际上正是经过document.getElementById查询之后然后查询它的子孙节点中的全部满意tagName为input的因素;而#aaa
>
input这种正是询问它的孩子节点中是还是不是有这种知足条件的成分。现在全部工艺流程比较轻便了,对于贰个繁杂查询,首先进行一个简短询问,然后依照查询的结果群集,举办一次遍历,对各类节点查询它的孩子节点或子孙节点,将具有满足条件的放入到其它叁个数组,若是该数组为空,那么直接重临空数组,不然,继续开展下叁回询问(依旧查询孩子节点或子孙节点卡塔尔国。

         
 小编以为,就那样一个功力比较轻巧的query就够了,不供给完成肖似于jquery里面包车型地铁这么繁复的查询,假使要接收它,其实也相当的粗略,因为jquery的询问引擎sizzle已经开源,完全能够将它加入到这一个库,而将来toper也是那般做的,要调用sizzle就接受:

tp.use("tp.dom.sizzle",function(sizzle) {});

         
感觉JS的包容性真心超级高烧啊,就比方在DOM这一道,为了合作,小编都做了十分长日子。当然,DOM这一齐早晚不仅仅这么一点内容,暂且也不写了。

          除了DOM,对变量类型的判别和浏览器的检验也是很要紧的。

       
 首先,类型推断,由于JS是弱类型语言,而不经常候是索要看清它的类别的,当然也足以运用typeof
去剖断,临时作者是这么做的:

  

tp.type = tp.type || {};
tp.type.isArray = function(ele) {
    return "[object Array]" === Object.prototype.toString.call(ele);
};
tp.type.isFunction = function(ele) {
    return "[object Function]" === Object.prototype.toString.call(ele);
};
tp.type.isObject = function(ele) {
    return ("function" === typeof ele) || !!(ele && "object" === typeof ele);
};
tp.type.isString = function(ele) {
    return "[object String]" === Object.prototype.toString.call(ele);
};
tp.type.isNumber = function(ele) {
    return "[object Number]" === Object.prototype.toString.call(ele) && isFinite(ele);
};
tp.type.isBoolean = function(ele) {
    return "boolean" === typeof ele;
};
tp.type.isElement = function(ele) {
    return ele && ele.nodeType == 1;
};
tp.type.isUndefined = function(ele) {
    return "undefined" === typeof ele;
};

       
笔者看了弹指间,分歧的库的论断情势不肖似,小编此刻使用的是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);
})();

     
 当然,还应该有浏览器版本的剖断,方今就不贴出来了。这里基本思路正是剖断navigator.useAgent重返的字符串中,各种浏览器里面包车型大巴那么些字符串是不均等的,当然,这么些进度相比较恶心,何况有望后边某一个浏览器会退换它的userAgent,引致整个决断失效,譬喻IE,听外人说后边新IE要把userAgent搞成firefox,真心搞不懂,那是要逆天啊?

     
 除了这种论断情势,还是能透过判断是或不是有某多个函数或某三个变量来决断,这种推断格局本人忘掉叫什么名字了,反正以前这种叫浏览器嗅探。

     
 除了代码之外,工具也很关键,另意气风发篇日记介绍JS工具的:

       
对动漫有野趣的童鞋,能够看看作者的近日学习JS的清醒-2,关于动漫的。

     
 可以吗,貌似又超时了,先就像此吗,感到每便写这种日志都会花费数不胜数岁月。

发表评论

电子邮件地址不会被公开。 必填项已用*标注