特征嗅探模块。基本取自jQuery,再加入一些与我的方法相关的特征嗅探。jQuery对DOM的研究非常深入,尤其是其clean与clone方法所带动对节点的生成技术研究,比其他类库高出一截。各种稀奇古怪的BUG都被它发掘出来了。为了对付这些BUG,support模块就是做这些先头工作的重要模块了。
//========================================== // 特征嗅探模块 by 司徒正美 //========================================== (function(global,DOC){ var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')]; dom.define("support", function(){ dom.log("已加载support模块"); var div = DOC.createElement('div'),TAGS = "getElementsByTagName"; div.innerHTML = ' <link/><a href="/nasami" class="u" style="float:left;opacity:.25;">d</a>'+ '<object><param/></object><table></table><input type="checkbox"/>'; var a = div[TAGS]("a")[0], style = a.style, select = DOC.createElement("select"), opt = select.appendChild( DOC.createElement("option") ); var support = dom.support = { //是否支持自动插入tbody insertTbody: !!div[TAGS]("tbody").length, // checkbox的value默认为on,唯有Chrome 返回空字符串 checkOn : div[TAGS]( "input" )[ 0 ].value === "on", //safari下可能无法取得这个属性,需要访问一下其父元素后才能取得该值 attrSelected:!!opt.selected, //是否区分href属性与特性 attrHref: a.getAttribute("href") === "/nasami", //IE67是没有style特性(特性的值的类型为文本),只有el.style(CSSStyleDeclaration)(bug) attrStyle:a.getAttribute("style") !== style, //IE8,FF能直接用getAttribute("class")取得className,而IE67则需要将"class"映射为"className",才能用getAttribute取得 attrProp:a.getAttribute("className") !== "u", //http://www.cnblogs.com/rubylouvre/archive/2010/05/16/1736535.html //IE8返回".25" ,IE9pp2返回0.25,chrome等返回"0.25" cssOpacity: style.opacity == "0.25", //某些浏览器不支持w3c的cssFloat属性来获取浮动样式,而是使用独家的styleFloat属性 cssFloat: !!style.cssFloat, //某些浏览器使用document.getElementByTagName("*")不能遍历Object元素下的param元素(bug) traverseAll: !!div[TAGS]("param").length, //https://prototype.lighthouseapp.com/projects/8886/tickets/264-ie-can-t-create-link-elements-from-html-literals //某些浏览器不能通过innerHTML生成link,style,script节点 createAll: !!div[TAGS]("link").length, //IE的cloneNode才是真正意义的复制,能复制动态添加的自定义属性与事件(可惜这不是标准,归为bug) cloneAll: false, optDisabled: false, boxModel: null, insertAdjacentHTML:false, innerHTML:false, fastFragment:false }; //当select元素设置为disabled后,其所有option子元素是否也会被设置为disabled select.disabled = true; support.optDisabled = !opt.disabled; if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { div.attachEvent("onclick", function click() { support.cloneAll = true;//w3c的节点复制是不复制事件的 div.detachEvent("onclick", click); }); div.cloneNode(true).fireEvent("onclick"); } //测试是否符合w3c的盒子模型 div.style.width = div.style.paddingLeft = "1px"; //判定insertAdjacentHTML是否完美,用于append,prepend,before,after等方法 var table = div[TAGS]("table")[0] try{ table.insertAdjacentHTML("afterBegin","<tr><td>1</td></tr>"); support.insertAdjacentHTML = true; }catch(e){ } try{ var range = DOC.createRange(); support.fastFragment = range.createContextualFragment("<a>") && range; }catch(e){ }; //判定innerHTML是否完美,用于html方法 try{ table.innerHTML = "<tr><td>1</td></tr>"; support.innerHTML = true; }catch(e){}; //有些特征嗅探必须连接到DOM树上才能进行 var body = DOC[TAGS]( "body" )[ 0 ],i, testElement = DOC.createElement( body ? "div" : "body" ), testElementStyle = { visibility: "hidden", 0, height: 0, border: 0, margin: 0, background: "none" }; if ( body ) { dom.mix( testElementStyle, { position: "absolute", left: "-1000px", top: "-1000px" }); } for ( i in testElementStyle ) { testElement.style[ i ] = testElementStyle[ i ]; } testElement.appendChild( div );//将DIV加入DOM树 var testElementParent = body || dom.html; testElementParent.insertBefore( testElement, testElementParent.firstChild ); support.boxModel = div.offsetWidth === 2; if ( "zoom" in div.style ) { //IE7以下版本并不支持display: inline-block;样式,而是使用display: inline; //并通过其他样式触发其hasLayout形成一种伪inline-block的状态 div.style.display = "inline"; div.style.zoom = 1; support.inlineBlockNeedsLayout = div.offsetWidth === 2; //http://w3help.org/zh-cn/causes/RD1002 // 在 IE6 IE7(Q) IE8(Q) 中,如果一个明确设置了尺寸的非替换元素的 'overflow' 为 'visible', // 当该元素无法完全容纳其内容时,该元素的尺寸将被其内容撑大 // 注:替换元素(replaced element)是指 img,input,textarea,select,object等这类默认就有CSS格式化外表范围的元素 div.style.display = ""; div.innerHTML = "<div style='4px;'></div>"; support.shrinkWrapBlocks = div.offsetWidth !== 2; } div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>"; var tds = div[TAGS]("td"), isSupported = ( tds[ 0 ].offsetHeight === 0 ); //只有IE8存在这个问题,那当td元素的display为none时,其高度依旧会受其所在行的高度的影响,而不是0 //这个问题的存在根本上导致了对元素可见性的判定出现差错 tds[ 0 ].style.display = ""; tds[ 1 ].style.display = "none"; support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); div.innerHTML = ""; testElementParent.removeChild( testElement ); div = tds = null; }); })(this, this.document); /** 2011.9.7 优化attrProp判定 2011.9.16所有延时判定的部分现在可以立即判定了 2011.9.23增加fastFragment判定 */