IE8兼容问题(1)

背景

今天在做项目时发现IE8的console.log返回错误,以及IE8不支持getElementsByClassName方法,并且在对document.getElementByClassName赋值给变量后无法调用,因此写下本篇文章用于记录今日的问题,并且探究问题的解决方案。

问题

1.console.log返回错误

<script>
    console.log(1);
</script>

以上代码段运行在IE8/9内核环境下会返回console未定义异常。😫

IE8 console错误截图

但是在我打开F12开发者工具之后刷新页面又不会出现以上异常,这让我烦恼不已。然后在网络上搜索资料发现IE8/9在开启开发者工具时不会构造console对象,因此会出现异常。

解决方案:

1.删除在程序内部的console对象
2.为console对象初赋值。

//将console对象在console未定义时初始化为一个空方法对象,避免IE8/9报错
window.console=window.console||(function(){
      var c = {};
      c.log=c.info=c.assert=c.error=c.dir=c.clear=c.profile=c.warn=
      c.profileE=function(){}
      return c;
})();

2.IE8不支持document.getElementsByClassName

今日做开发的时候写了一个IE8的兼容实现,在对DOM操作时使用了document.getElementsByClassName来获取对象,然而却返回了错误,当时一脸懵逼,没想到IE8连如此通用的方法都没支持,先撒撒气,然后就查看兼容性实现方法。。。😢

//所书写的代码段
var delegator = documents.getElementsByClassName('content-left')[0],//报错
      isIE = typeof document.all === 'undefined'?false:true;//判断是否是IE
if(isIE){
IEFunc();               
}
else{
OtherFunc();
}
解决方案:

1.通过自实现的代码解决方案(大多参考网上的解决方案)。

//通过遍历所有标签进行判断处理(粗暴的处理方式,在对于大量标签页面的处理明显是不可取的)
document.getElementsByClassName = document.getElementsByClassName||function(value){
    var arr = [];
    var all = document.getElementsByTagName('*');
    for(var i=0,len=all.length;i<len;i++){
        var temp = all[i].getAttribute('class');
        if(temp&&temp.indexOf(value)>=0){
            arr.push(all[i]);
        }
    }
    return arr;
};

2.其他大神或者框架的处理方案。(本小节内容多摘自司徒正美的博客)
The Ultimate getElementsByClassName方案,作者为Robert Nyman,05年实现。

//三个参数都是必需的,查找一网页中5007个类名为“cell”的元素,IE8历时1828 ~ 1844毫秒
function getElementsByClassName(oElm, strTagName, strClassName){
//oElm DOM对象,strTagName 查找对象的Tag名,strClassName 查找对象的类名

    var arrElements = (strTagName == "*" && oElm.all)? oElm.all :
        oElm.getElementsByTagName(strTagName);
    //oElm.all可获取所有DOM对象, (Tips1)
    
    var arrReturnElements = new Array();
    strClassName = strClassName.replace(/\-/g, "\\-");
    var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
    //用于判断类名的正则,匹配开头或空格+类名+空格或结尾

    var oElement;
    for(var i=0; i < arrElements.length; i++){
        oElement = arrElements[i];
        if(oRegExp.test(oElement.className)){
            arrReturnElements.push(oElement);
        }
    }
    return (arrReturnElements);
}

Tips1:typeof document.all 在IE下返回'object',在其他浏览器下返回'undefined'。

另一个实现,由Dustin Diaz(《JavaScript Design Patterns》的作者)提供,但兼容性不如上面的,不支持IE5。

//后两参数是可靠的,查找一网页中5007个类名为“cell”的元素,IE8历时78毫秒,IE6历时125~171毫秒
var getElementsByClass = function(searchClass,node,tag) {
        var classElements = new Array();
        if ( node == null )
                node = document;
        if ( tag == null )
                tag = '*';
        var els = node.getElementsByTagName(tag);
        var elsLen = els.length;
        var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
        for (i = 0, j = 0; i < elsLen; i++) {
                if ( pattern.test(els[i].className) ) {
                        classElements[j] = els[i];
                        j++;
                }
        }
        return classElements;
}

还有个更古老级的,司徒正美前辈从prototype.js1.01版本中找到的,它能支持多个类名的查找(上面两个不行)。它不支持IE5,效率一般般,但作为最早的框架之一,它已经做得很好,其他框架还没有想到这个呢!

function getElementsByClassName(className, element) {
    var children = (element || document).getElementsByTagName('*');
    var elements = new Array();

    for (var i = 0; i < children.length; i++) {
        var child = children[i];
        var classNames = child.className.split(' ');
        for (var j = 0; j < classNames.length; j++) {
            if (classNames[j] == className) {
                elements.push(child);
                break;
            }
        }
    }

    return elements;
}

后续还介绍了DOMTreeWalker 和 XPath的解决方案,但是我还没又这方面的知识就不在此处贴出了,感兴趣的同学可以浏览上面司徒正美的博客。接下来给出司徒正美前辈给出的最终解决方案:

//下列代码可以解决‘red cell’ 对<span class="cell red"></span>等特殊class情况的检索
var getElementsByClassName = function (searchClass, node,tag) {
  if(document.getElementsByClassName){
    var nodes =  (node ||   document).getElementsByClassName(searchClass),result = [];
      for(var i=0 ;node = nodes[i++];){
        if(tag !== "*" && node.tagName === tag.toUpperCase()){
          result.push(node)
        }
      }
      return result
    }else{
      node = node || document;
      tag = tag || "*";
      var classes = searchClass.split(" "),
      elements = (tag === "*" && node.all)? node.all : node.getElementsByTagName(tag),
      patterns = [],
      current,
      match;
      var i = classes.length;
      while(--i >= 0){
        patterns.push(new RegExp("(^|\\s)" + classes[i] + "(\\s|$)"));
      }
      var j = elements.length;
      while(--j >= 0){
        current = elements[j];
        match = false;
        for(var k=0, kl=patterns.length; k<kl; k++){
          match = patterns[k].test(current.className);
          if (!match)  break;
        }
        if (match)  result.push(current);
        }
      return result;
    }
  }

3.document.method赋值给变量后调用报错

在写兼容性代码时曾考虑将document.method赋值给变量的方式来返回兼容性结果,然而在chrome浏览器运行时异常抛出Illegal invocation

//测试代码
var getClass = document.getElementsByClassName;
getClass('class');
chrome错误内容

然而在IE8下运行上述方法奇迹般的成功了。。。😢

IE8内核下运行结果

IE9下测试则报错。

IE9内核下运行结果

而在chrome下使用

 getClass.call(document,'class'); //运行成功 图片就不上了 有兴趣的同学可以自己测试

然而非设置this为document而未其他Dom节点时就会报错,其中细节搜索资料并为找到原因,如果有大牛还请讲解原由。🙏

总结

上面总结了今日所遇到的IE8兼容性问题,有自己探索的结果也有网上搜罗的资料,虽然有些内容没有啥可用性但是作为程序员一定要有专研和探究的精神。😄 如上述问题有错误或还请大牛贴上讲解地址或者留言,感激不敬🙏,本文目的在于分享与交流,如要引用还望指明出处,谢谢。
转眼间要12点了,第一次写如此长的文章😊,希望记录今日的问题,该洗洗睡了,明天还要上班咧😄。
行文仓促,如有问题还望指出。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • DOM DOM内容主要分为四部分: 什么是DOM和节点; 获取节点; 节点操作(3种); 属性操作(3种)。 什么...
    magic_pill阅读 820评论 0 1
  • 本博客转自:「作者:若愚链接:https://zhuanlan.zhihu.com/p/22361337来源:知乎...
    韩宝亿阅读 2,826评论 0 3
  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,964评论 2 17
  • 参加了人人都是产品经理组织的2天产品大会,坐标深圳宝安。按照这两天嘉宾分享整理的一些分享内容和个人看法。收获满满,...
    小林同学90阅读 442评论 0 1
  • “炫耀性消费”是指富裕的上层阶级通过对物品的超出实用和生存所必需的浪费性、奢侈性和铺张浪费,向他人炫耀和展示自己的...
    晓妮臆空间阅读 2,389评论 0 1