自定义标签在IE6,最近学习JS的感悟

自定义标签在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),而其余的零件每一个组件一个文本,而组件之间大概存在依据关系,这种注重关系就因而AMD消弭。

      在尚未写那么些库此前,固然是自家利用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的第贰个参数是该零件的名字(供给唯生龙活虎,所以自个儿大概依据命名空间的模式写的),首个参数是以此组件所依靠的组件,第二个参数是回调函数,也正是当重视的零部件下载达成现在,回调实践,而tp.modules.add就足以将以此模块加载到总体库中,那样的话本领应用tp.use调用。

      这种艺术自个儿在tangram中未有看出,作者是看了Tmall的KISSY之后攻读到的,也正是所谓的英特尔(异步模块定义)。

      临时英特尔的得以完成形式是透过setInterval,但是将要被重构图片 10

      笔者事先写了生机勃勃篇日记来促成英特尔,当然,成效低下,反正我们看看就行了

      然后正是事件了,事件是多少个相比较恼火的事务,东西相当多,小编把它位于了tp.event那个空间中。

      首先是拉长和移除事件监听器,由于IE和非IE采纳的办法分裂等,IE选拔attachEvent和detech伊夫nt,非IE选取add伊芙ntListener和removeEventListener,并且IE只支持冒泡(从当下成分冒泡到根成分),而非IE支持冒泡和破获(从根成分捕获到最近因素)。最开头小编是这么做的:

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,关于动画的。

       可以吗,貌似又超时了,先就那样呢,以为每趟写这种日志都会消耗数不完时光。

本文由365bet体育在线官网发布于前端技术,转载请注明出处:自定义标签在IE6,最近学习JS的感悟

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。