IE6的base标签导致页面结构大混乱

这是一个非常隐秘也是非常强大的bug,我真不知微软的IE开发人员是怎么搞出来的。此bug的触发条件是,当页面存在一个自闭合的base节点,它就会把其“下面”所有的元素都拷到它内部。这里的下面非childNodes,children所能描述,它连body节点都能编入其中。

<!doctype html>
<html>
  <head>
    <meta charset="utf-8"/>
    <meta content="IE=8" http-equiv="X-UA-Compatible"/>
    <meta name="keywords" content="IE6 base bug" />
    <base href='http://www.cnblogs.com/rubylouvre/' />
    <script type="text/javascript" id="test">
      window.onload = function(){
        var meta = document.createElement("meta");
        meta.name = "description";
        meta.content = "IE6 base bug by 司徒正美"
        var head = document.documentElement.firstChild;
        head.appendChild(meta);
        alert("meta.parentNode : "+meta.parentNode.tagName);
        var base = document.getElementsByTagName("base")[0];
        alert("base.childNodes.length : "+base.childNodes.length)
        alert("body.parentNode : "+document.body.parentNode.tagName)
        var script = document.getElementById("test");
        alert("script.parentNode : "+script.parentNode.tagName)
      }
    </script>
    <title>IE 复制节点 bug</title>
  </head>
  <body>
    <h1>请在IE6下运行</h1>
    <script type='text/javascript'
  </body>
  
</html>

<!doctype html> <html> <head> <meta charset="utf-8"/> <meta content="IE=8" http-equiv="X-UA-Compatible"/> <meta name="keywords" content="IE6 base bug" /> <base href='http://www.cnblogs.com/rubylouvre/' /> <script type="text/javascript" id="test"> window.onload = function(){ var meta = document.createElement("meta"); meta.name = "description"; meta.content = "IE6 base bug by 司徒正美" var head = document.documentElement.firstChild; head.appendChild(meta); alert("meta.parentNode : "+meta.parentNode.tagName); var base = document.getElementsByTagName("base")[0]; alert("base.childNodes.length : "+base.childNodes.length) alert("body.parentNode : "+document.body.parentNode.tagName) var script = document.getElementById("test"); alert("script.parentNode : "+script.parentNode.tagName) } </script> <title>IE 复制节点 bug</title> </head> <body> <h1>请在IE6下运行</h1> <script type='text/javascript' src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script> </body> </html>

运行代码

运行代码下,我们发现完全乱套了,原本父节点为head的meta元素(动态生成)与父节点为html的body元素(原来就存在),它们的父节点都变成base节点。下面是用firebug lite截到的图:

jQuery在使用globalEval方法动态解析脚本时,就遇到这个问题,它取巧地把动态生成的script节点插入到base节点之前。

globalEval: function( data ) {
    if ( data && rnotwhite.test(data) ) {
        var head = document.getElementsByTagName("head")[0] || document.documentElement,
        script = document.createElement("script");
        script.type = "text/javascript";
        if ( jQuery.support.scriptEval ) {
            script.appendChild( document.createTextNode( data ) );
        } else {
            script.text = data;
        }
        head.insertBefore( script, head.firstChild );
        head.removeChild( script );
    }
},

但还是不妥当,因为始终留着个陷阱给人踩。想了想,base标签无碍乎只有两个属性,用于对页面上所有的URL进行统一设置,如img.src,form.action,a.href等等。通常只有一个就够了,如果它只存在于body中,不管,如果存在于head就会为害人间了,我们需要将它强制添加一个闭合标签。即,将它由

转换为

<base href='http://www.cnblogs.com/rubylouvre/' ></base>

虽然IE6解析base的半闭合形式出错,但它不会不济到解析一个全新的节点出错吧,它理应会把新节点转换为它不会出错的形式,换言之,是第二种形式。创建新节点的方法有许多种,但我们很需要原节点的属性,恰好IE的cloneNode什么也能复制。之后就是插入节点的问题了,我们使用它的一个私有实现replaceNode,不用知晓其父节点,它也将用于区分IE与非IE。

下面是我的fixbug程序:

//by 司徒正美
//此bug在IE7中修复,详见:
        if(document.replaceNode && !window.XMLHttpRequest){
          var head = document.getElementsByTagName("head")[0],
          base = head.getElementsByTagName("base")[0],
          headFrag = document.createDocumentFragment(),
          bodyFrag = headFrag.cloneNode(),el;
           if(base && base.childNodes.length){
            for (; el =base.childNodes[0];) {
              if(el.tagName === "BODY"){
                bodyFrag.appendChild(el);
                break;
              }else{
                headFrag.appendChild(el)
              }
            }
            base.replaceNode(base.cloneNode())
            head.appendChild(headFrag);
            document.documentElement.appendChild(bodyFrag)
          }
        }

<!doctype html> <html> <head> <meta charset="utf-8"/> <meta content="IE=8" http-equiv="X-UA-Compatible"/> <meta name="keywords" content="IE6 base bug" /> <base href='http://www.cnblogs.com/rubylouvre/' /> <script type="text/javascript" id="test"> window.onload = function(){ if(document.replaceNode && !window.XMLHttpRequest){ var head = document.getElementsByTagName("head")[0], base = head.getElementsByTagName("base")[0], headFrag = document.createDocumentFragment(), bodyFrag = headFrag.cloneNode(),el; if(base && base.childNodes.length){ for (; el =base.childNodes[0];) { if(el.tagName === "BODY"){ bodyFrag.appendChild(el); break; }else{ headFrag.appendChild(el) } } base.replaceNode(base.cloneNode()) head.appendChild(headFrag); document.documentElement.appendChild(bodyFrag) } } // =================测试代码========== var meta = document.createElement("meta"); meta.name = "description"; meta.content = "IE6 base bug by 司徒正美" var head = document.documentElement.firstChild; head.appendChild(meta); alert("meta.parentNode : "+meta.parentNode.tagName); var base = document.getElementsByTagName("base")[0]; alert("base.childNodes.length : "+base.childNodes.length) alert("body.parentNode : "+document.body.parentNode.tagName) var script = document.getElementById("test"); alert("script.parentNode : "+script.parentNode.tagName) } </script> <title>IE 复制节点 bug</title> </head> <body> <h1>请在IE6下运行</h1> <script type='text/javascript' src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script> </body> </html>

运行代码

搞定!不过,我的globalEval函数用不着这个,直接用execScript一了百了,连script标签也不用插入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值