源码解读jQ中浏览器兼容模块support

 更新时间:2016年08月01日 12:04:21   投稿:daisy  
jquery support主要是检测浏览器兼容性,支持力度的方法,用于展示不同浏览器各自特性和bug的属性集合。作为一个静态成员,提供给jquery内部函数,告诉他们某些功能是否能用。避免了以往通过检测浏览器版本做修改。下面我们通过源码详细解读jQ中浏览器兼容模块support。
//这样的写法在浏览器中根本不生效;document.body.innerHTML = "<script src='1.js'></script>"//但是我们可以通过jQuery的方式生成并插入到DOM数种$("<script src='1.js'></script>").appendTo(document.body)

$.support.style

标准浏览器通过getAttribute获取都应该是字符串的,IE67你getAttriute是各种奇葩,你获取的style是一整个样式对象, IE67要获取行内样式要用  eDiv.style.cssText  才行哦

<html>  <head>    <meta charset="utf-8" />    <title>兼容</title>  </head>  <body>    <script type="text/javascript">      window.l = (function() {        var el = document.createElement("div"), index = 0;        el.style.cssText = "padding:10px;position:fixed;top:0;right:0;width:10%;border:1px solid #f00;";        return function(message) {          message = message.toString();          if( message ) {            var span = document.createElement("span");            span.innerHTML = (++index) + "信息:<br>"+ message+"<br>";            el.appendChild( span );          };          //IE低版本直接通过createElement创建的元素有parentNode;          if( !el.parentNode || (el.parentNode.toString() === "[object]") ) {            document.body.appendChild(el);          };          return l;        };      })();    </script>    <div id="div" style="background:#f00;" onclick="fn">      divide    </div>    <div id="link"></div>    <script type="text/javascript">      var fn = function() {        alert(1);      };      var eDiv = document.getElementById("div");      //标准浏览器要么返回的是background:#f00,要么返回background: rgb(255, 0, 0);      //IE6,IE7返回了所有的style属性      l(eDiv.getAttribute("style"));      l(typeof eDiv.getAttribute("onclick"));    </script>  </body></html>

IE67中获取style返回的是下面图片, 这个应该是eDiv的元素属性才对, 意思就是说IE67中DOM属性和节点属性傻傻分不清楚, 比如onclick返回的是function….(等等,我想静静….):

获取一个html页面的相对路径可以通过动态创建一个锚链接,然后获取这个锚连接的href就可以获取到绝对的路径, 浏览器获取script标签的src方式要根据浏览器的特性,一般来说是这样的:

document.querySelector ? node.src : node.getAttribute(“src”,4);

<html>  <head>    <meta charset="utf-8" />    <title>兼容</title>  </head>  <body>    <script type="text/javascript">      window.l = (function() {        var el = document.createElement("div"), index = 0;        el.style.cssText = "padding:10px;position:fixed;top:0;right:0;width:10%;border:1px solid #f00;";        return function(message) {          message = message.toString();          if( message ) {            var span = document.createElement("span");            span.innerHTML = (++index) + "信息:<br>"+ message+"<br>";            el.appendChild( span );          };          //IE低版本直接通过createElement创建的元素有parentNode;          if( !el.parentNode || (el.parentNode.toString() === "[object]") ) {            document.body.appendChild(el);          };          return l;        };      })();    </script>    <a id="a" href="./xx.html"></a>    <script id="js" src="xx.js"></script>    <div id="link"></div>    <script type="text/javascript">      var fn = function() {        alert(1);      };      //反正你通过属性的方式获取a锚连接的href都是绝对路径,getAttribute都是开发者输入的字符串,      var eA = document.getElementById("a");      l(eA.getAttribute("href",3));      l(eA.href);      var js = document.getElementById("js");      //IE8以后和标准浏览器获取绝对的src直接通过src,IE67通过src获取绝对路径, 这个技巧在获取script标签的src时候会用到;      l(js.getAttribute("src",4));      l(js.src);    </script>  </body></html>

$.support.opacity

opacity这个玩意儿到了IE9才支持, IE678只能用滤镜:filter:opacity(alpha=10);

<html>  <head>    <meta charset="utf-8" />    <title>兼容</title>  </head>  <body>    <script type="text/javascript">      window.l = (function() {        var el = document.createElement("div"), index = 0;        el.style.cssText = "padding:10px;position:fixed;top:0;right:0;width:10%;border:1px solid #f00;";        return function(message) {          message = message.toString();          if( message ) {            var span = document.createElement("span");            span.innerHTML = (++index) + "信息:<br>"+ message+"<br>";            el.appendChild( span );          };          //IE低版本直接通过createElement创建的元素有parentNode;          if( !el.parentNode || (el.parentNode.toString() === "[object]") ) {            document.body.appendChild(el);          };          return l;        };      })();    </script>    <div style="position: absolute;">      1111    </div>    <div style="opacity:0.2;float:left">      对对对    </div>    <script type="text/javascript">      l("haha");    </script>  </body></html>

$.support.cssFloat

这个玩意儿标准浏览器是cssFloat, IE中要用styleFloat,比如:

element.style.cssFloat;element.style.styleFloat;

$.support.optSelected

<html>  <head>    <meta charset="utf-8" />    <title>兼容</title>  </head>  <body>    <script type="text/javascript">      window.l = (function() {        var el = document.createElement("div"), index = 0;        el.style.cssText = "padding:10px;position:fixed;top:0;right:0;width:10%;border:1px solid #f00;";        return function(message) {          message = message.toString();          if( message ) {            var span = document.createElement("span");            span.innerHTML = (++index) + "信息:<br>"+ message+"<br>";            el.appendChild( span );          };          //IE低版本直接通过createElement创建的元素有parentNode;          if( !el.parentNode || (el.parentNode.toString() === "[object]") ) {            document.body.appendChild(el);          };          return l;        };      })();    </script>    <script type="text/javascript">    select = document.createElement("select");    var opt;    //创建optino元素的方法1:    //opt = document.createElement("option");    //opt.setAttribute("value","value");    //opt.setAttribute("name","name");    //(opt.textContent = "text")|| (opt.innerText = "text");    //创建optino元素的方法2:    //这样也可以;    //opt = document.createElement("option");    //opt.value = "value";    //opt.text = "text";    //这样也行;    //创建optino元素的方法3:    opt = new Option("text","value");    select.appendChild( opt );    document.getElementsByTagName("body")[0].appendChild(select);    l( opt.selected );    </script>  </body></html>

$.support.getSetAttribute

IE67可以用setAttribute设置className的class, 出了IE67以外的浏览器可以用setAttribute(class,”")设置class

<html>  <head>    <meta charset="utf-8" />    <title>兼容</title>  </head>  <body>    <script type="text/javascript">      window.l = (function() {        var el = document.createElement("div"), index = 0;        el.style.cssText = "padding:10px;position:fixed;top:0;right:0;width:10%;border:1px solid #f00;";        return function(message) {          message = message.toString();          if( message ) {            var span = document.createElement("span");            span.innerHTML = (++index) + "信息:<br>"+ message+"<br>";            el.appendChild( span );          };          //IE低版本直接通过createElement创建的元素有parentNode;          if( !el.parentNode || (el.parentNode.toString() === "[object]") ) {            document.body.appendChild(el);          };          return l;        };      })();    </script>    <script type="text/javascript">    div = document.createElement("div");    div.setAttribute( "className", "t" );    l(div.className !== "t");    /*    div.setAttribute( "class", "t" );    l(div.className == "t");    */    </script>  </body></html>

$.support.html5Clone

IE6新建一些无法识别的标签时候会出现问题,比如

<script type="text/javascript">l(document.createElement("nav").cloneNode( true ).outerHTML);</script>

在IE6中执行会变成这样:

, 而且这个特性在IE11模拟IE5,IE6一点效果都没有;

小技巧为了让IE6支持HTML5的标签可以自己创建html5标签,而且你可以给这些标签自定义样式:

<html>  <head>    <meta charset="utf-8" />    <title>兼容</title>  </head>  <body>    <script>    (function(){      var element=['header','footer','article','aside','section','nav','menu','hgroup','details','dialog','figure','figcaption'],        len=element.length;      while(len--){        document.createElement(element[len])      };     })();     </script>    <style>    nav{      width:100px;      height:100px;      background:#f00;      display:block;    }    </style>    <nav>nav</nav>    <footer>footer</footer>    <script type="text/javascript">      window.l = (function() {        var el = document.createElement("div"), index = 0;        el.style.cssText = "padding:10px;position:fixed;top:0;right:0;width:10%;border:1px solid #f00;";        return function(message) {          message = message.toString();          if( message ) {            var span = document.createElement("span");            span.innerHTML = (++index) + "信息:<br>"+ message+"<br>";            el.appendChild( span );          };          //IE低版本直接通过createElement创建的元素有parentNode;          if( !el.parentNode || (el.parentNode.toString() === "[object]") ) {            document.body.appendChild(el);          };          return l;        };      })();    </script>    <script type="text/javascript">    l(document.createElement("nav").cloneNode( true ).outerHTML);    </script>  </body></html>

$.support.boxModel

这个玩意儿 document.compatMode === “‘BackCompat'”  是为了让我们知道当前的文档模式是否是标准的文档模式,还是有用的;

$.support.submitBubbles, $.support.changeBubbles, $.support.focusinBubbles

除了火狐以外所有的浏览器都支持focusin和focusout, 这两个事件和focus和blur的区别是, focus和blur并不会发生冒泡,focusin和focusout会冒泡, 我们可以通过focusin和focusout实现事件代理, 例子:

<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title>focus(in|out) not implemented</title> <script type="text/javascript">//<![CDATA[  document.addEventListener('focusin',function(e){if(e.target.tagName=='INPUT')e.target.style.backgroundColor='green'},0)  document.addEventListener('focusout',function(e){if(e.target.tagName=='INPUT')e.target.style.backgroundColor='white'},0) //]]></script> </head> <body> <div><input type="text" style="background:red" /></div> <div>Please click on input above to change element color.</div> <div><a href="http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#event-type-focusIn">http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#event-type-focusIn</a></div> <div style="color:red">Firefox: not implemented yet!</div> <div style="color:green">IE 9: focused in - green</div> <div style="color:green">Opera 11.5: focused in - green</div> <div style="color:green">Chrome 14: focused in - green</div> <div style="color:green">Safari 5.1: focused in - green</div> <div>Konqueror 4.7: only DOMFocus</div> </body></html>

虽然就只有firefox不支持focusin, 但是support.focusinBubbles在ff,chrome,以及IE11中的值都为false, 也就是说jQuery把他们都统一起来,通过focusblur的的自定义代理模拟focusinfocusout

因为ie6-ie10中都支持attachEvent方法,所以focusinBubble都为true, IE11不支持attachEvent,所以focusinBubblefalse了;

submitBubbleschangeBubbles在IE8以下的浏览器中都是false;

结果的确有点乱, 在后面的事件系统中不支持事件冒泡是要做特殊处理的,下面这个代码从jQ中切出来( ̄_, ̄ )的代码;

<html>  <head>    <meta charset="utf-8" />    <title>兼容</title>  </head>  <body>    <script>      window.l = (function() {        var el = document.createElement("div"), index = 0;        el.style.cssText = "padding:10px;position:fixed;top:0;right:0;width:10%;border:1px solid #f00;word-break:break-all";        return function(message) {          message = message.toString();          if( message ) {            var span = document.createElement("span");            span.innerHTML = (++index) + "信息:<br>"+ message+"<br>";            el.appendChild( span );          };          //IE低版本直接通过createElement创建的元素有parentNode;          if( !el.parentNode || (el.parentNode.toString() === "[object]") ) {            document.body.appendChild(el);          };          return l;        };      })();        //写了一个小小的JSON方法,哈哈o(^▽^)o,666666666666666      if(!window.JSON) {        window.JSON = {          stringify : function(json) {            var str = "{";            for(var p in json) {              if( typeof json[p] === "object") {                str += (p+":"+ window.JSON.stringify(json[p]) +",");              }else {                str += (p+":"+String(json[p])+",")              };            };            return str.slice(0,-1)+"}";          }        }      };      //testing;      l( JSON.stringify({1:{2:3,4:{5:"six"}}}) );    </script>    <script type="text/javascript">    var support = {      submitBubbles: true,      changeBubbles: true,      focusinBubbles: false    };    var div = document.createElement("div");    if ( div.attachEvent ) {      for ( i in {        submit: true,        change: true,        focusin: true      }) {        eventName = "on" + i;        isSupported = ( eventName in div );        if ( !isSupported ) {          div.setAttribute( eventName, "return;" );          isSupported = ( typeof div[ eventName ] === "function" );        };        support[ i + "Bubbles" ] = isSupported;      };    };    l( JSON.stringify(support) );    </script>  </body></html>

$.support.deleteExpando

因为IE6和IE7下的DOM元素是COM组件,delete删除COM组件的属性会报错,所以有了deleteExpando这个玩意儿,DEMO

<html>  <head>    <meta charset="utf-8" />    <title>兼容</title>  </head>  <body>    <div id="id"></div>    <script>      window.l = (function() {        var el = document.createElement("div"), index = 0;        el.style.cssText = "padding:10px;position:fixed;top:0;right:0;width:10%;border:1px solid #f00;word-break:break-all";        return function(message) {          message = message.toString();          if( message ) {            var span = document.createElement("span");            span.innerHTML = (++index) + "信息:<br>"+ message+"<br>";            el.appendChild( span );          };          //IE低版本直接通过createElement创建的元素有parentNode;          if( !el.parentNode || (el.parentNode.toString() === "[object]") ) {            document.body.appendChild(el);          };          return l;        };      })();      var id = document.getElementById("id");      id.test = "1111";      try {        delete id.test;      } catch( e ) {        l( "delete错误" );      };    </script>  </body></html>

$.support.noCloneEvent

又是IE, 复制元素会把事件复制过去,support.noCloneEvent就是检测IE是否会复制元素的事件的属性, 因为jQuery中元素的事件是和数据缓存系统($.data,$.cahce)紧密耦合的, 要复制一个元素的事件直接复制元素的expanDo就可以, 事件并不是直接绑定到元素上的, 相关的JS代码:

    if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {      div.attachEvent( "onclick", clickFn = function() {        // Cloning a node shouldn't copy over any        // bound event handlers (IE does this)        support.noCloneEvent = false;      });      div.cloneNode( true ).fireEvent("onclick");      div.detachEvent( "onclick", clickFn );    }$.support.reliableHiddenOffsets

reliableHiddenOffsets这个是很少见的一个问题, 在IE7和IE6中出现bug, 如果一个table中有一个有内容的td的display为none, 这个table其他的td没有内容但是是显示着的话,那么这些td的高度为1, 这个1不知道是从哪里来的,很怪的一个bug(然道是空格?), 不管了, 反正用的少

<html>  <head>    <meta charset="utf-8" />    <title>兼容</title>  </head>  <body>  </body>    <script>      window.l = (function() {        var el = document.createElement("div"), index = 0;        el.style.cssText = "padding:10px;position:fixed;top:0;right:0;width:10%;border:1px solid #f00;word-break:break-all";        return function(message) {          message = message.toString();          if( message ) {            var span = document.createElement("span");            span.innerHTML = (++index) + "信息:<br>"+ message+"<br>";            el.appendChild( span );          };          //IE低版本直接通过createElement创建的元素有parentNode;          if( !el.parentNode || (el.parentNode.toString() === "[object]") ) {            document.body.appendChild(el);          };          return l;        };      })();    </script>    <script type="text/javascript">      var container = document.createElement("div");      var div = document.createElement("div");      var isSupported;      var body = document.getElementsByTagName("body")[0];      body.insertBefore( container, body.firstChild );      container.appendChild( div );      div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";      tds = div.getElementsByTagName("td");      tds[0].style.cssText = "padding:0;margin:0;border:0;display:none";      isSupported = (tds[0].offsetHeight === 0);      tds[0].style.display = "";      tds[1].style.display = "none";      isSupported = isSupported && ( tds[ 0 ].offsetHeight === 0 );      l( isSupported );    </script></html>

$.support.boxSizing,$.support.doesNotIncludeMarginInBodyOffset

IE8中是支持box-sizing的,IE6,IE7通过开启怪异模式也是支持boxSizing的;doesNotIncludeMarginInBodyOffset很不常用, 一般的offsetLeft或者offsetTop是从边框外开始计算的,也就是包含了margin, 但是因为body这个元素的特殊性质,body的offsetTop和offsetLeft并不包含margin,而且body一般有一个默认8px的marign, 导致计算位置的时候会产生混乱, so, jQ把他们统一起来了,doesNotIncludeMarginInBodyOffset这个在任何浏览器中都未true,(哎,放心了,我的小心肝都快碎了);

<html>  <head>    <meta charset="utf-8" />    <title>兼容</title>  </head>  <body>  </body>    <script>      window.l = (function() {        var el = document.createElement("div"), index = 0;        el.style.cssText = "padding:10px;position:fixed;top:0;right:0;width:10%;border:1px solid #f00;word-break:break-all";        return function(message) {          message = message.toString();          if( message ) {            var span = document.createElement("span");            span.innerHTML = (++index) + "信息:<br>"+ message+"<br>";            el.appendChild( span );          };          //IE低版本直接通过createElement创建的元素有parentNode;          if( !el.parentNode || (el.parentNode.toString() === "[object]") ) {            document.body.appendChild(el);          };          return l;        };      })();    </script>    <script type="text/javascript">      var div = document.createElement("div");      var body = document.getElementsByTagName("body")[0];      var support = {};      body.insertBefore( div, body.firstChild );      div.innerHTML = "";      div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";      support.boxSizing = ( div.offsetWidth === 4 );      support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );      l( support.boxSizing );      l( support.doesNotIncludeMarginInBodyOffset );    </script></html>

$.support.pixelPosition ,$.support.boxSizingReliable,$.support.reliableMarginRight

piexelPosition是指当你给一个元素设置百分比的宽度或者高度的时候, 通过getComputedStye标准浏览器都要返回像素的宽高, 有些浏览器返回的还是百分比的宽高, 这个bug应该是低版本的chrome或者ff才有的bug, IE(<=IE10)通过currentStyle获取的宽高返回的还是百分比的宽高, 要获取像素宽高需要hack…..,我想静静….;

boxSizingReliable这个也是再次验证盒模型是否支持, 不知道有什么用;

reliableMarginRight是指低版本chrome获取不到marginRight的问题,jQuery真是操碎了心;

<html>  <head>    <meta charset="utf-8" />    <title>兼容</title>  </head>  <body>  </body>    <script>      window.l = (function() {        var el = document.createElement("div"), index = 0;        el.style.cssText = "padding:10px;position:fixed;top:0;right:0;width:10%;border:1px solid #f00;word-break:break-all";        return function(message) {          message = message.toString();          if( message ) {            var span = document.createElement("span");            span.innerHTML = (++index) + "信息:<br>"+ message+"<br>";            el.appendChild( span );          };          //IE低版本直接通过createElement创建的元素有parentNode;          if( !el.parentNode || (el.parentNode.toString() === "[object]") ) {            document.body.appendChild(el);          };          return l;        };      })();    </script>    <script type="text/javascript">      var div = document.createElement("div");      var body = document.getElementsByTagName("body")[0];      var support = {};      body.insertBefore( div, body.firstChild );      div.innerHTML = "";      div.style.cssText = "width:50%";      if(window.getComputedStyle)        l( window.getComputedStyle(div,null)["width"] );      if(div.currentStyle) {        l( div.currentStyle["width"] );      }    </script></html>

$.support.inlineBlockNeedsLayout, $.support.shrinkWrapBlocks

在IE67浏览器,如果元素的display样式值为inline-block,并不会生效,要用display:inline;zoom:1;进行模拟, 所以inlineBlockNeedsLayout也是对于IE做的特殊处理;

shrinkWrapBlocks是因为在IE6中,子元素的宽度超过的父级元素,父元素的宽度也会被撑开,老问题。

<html>  <head>    <meta charset="utf-8" />    <title>兼容</title>  </head>  <body>  </body>    <script>      window.l = (function() {        var el = document.createElement("div"), index = 0;        el.style.cssText = "padding:10px;position:fixed;top:0;right:0;width:10%;border:1px solid #f00;word-break:break-all";        return function(message) {          message = message.toString();          if( message ) {            var span = document.createElement("span");            span.innerHTML = (++index) + "信息:<br>"+ message+"<br>";            el.appendChild( span );          };          //IE低版本直接通过createElement创建的元素有parentNode;          if( !el.parentNode || (el.parentNode.toString() === "[object]") ) {            document.body.appendChild(el);          };          return l;        };      })();    </script>    <div id="shrinkWrapBlocks" style="width: 1px; zoom: 1;">       <div style="width: 4px;">       </div>     </div>     <script type="text/javascript">       var div = document.getElementById('shrinkWrapBlocks'),       inner = div.getElementsByTagName('div')[0];       l(div.offsetWidth);     </script></html>

通过直接调用jQuery.support来检测某些功能,通过查看其源代码我们可以更深入的了解各个浏览器之间的区别。特别是针对IE,还有webkit的bug,都能让我们受益匪浅。本文内容到此就结束了,希望对大家学习jQuery有所帮助。

相关文章

最新评论