萬盛學電腦網

 萬盛學電腦網 >> 腳本專題 >> javascript >> javascript框架設計之浏覽器的嗅探和特征偵測

javascript框架設計之浏覽器的嗅探和特征偵測

  浏覽器的嗅探現在已經不推薦了,但在某些場合還是需要的。比如一些統計腳本。在標准浏覽器裡,提供了document.implementation.hasfeature,可惜有bug,不准確,目前,w3c又推出了CSS.supports方法,顯示出大家對這塊的關注。

  1.判定浏覽器。

  主流的浏覽器有ie firefox opera chorme safari 早期這些框架都是通過navigator.userAgent進行判定,目前國外的浏覽器幾乎都是可以判定的。

  關於浏覽器的判斷腳本,jQuery已經移出本體,形成一個插件。更多的方式不多介紹,

  移動設備的相關判定,這個建議看jQuery mobile與zepto的源代碼。

  代碼如下:

  isIPone = /isIPone/i.test(navigator.userAgent);

  isIPone4 = window.devicePixelRatio >= 2 //在網頁中,pixel與point比值稱為device-pixel-ratio,普通設備都是1,iPhone4是2,有些 安卓機型是1.5

  isIpad = /ipad/i.test(navigator.userAgent)

  isAndroid = /android/i.test(navigator.userAgent)

  isIOS = isIPone || isIpad

  國內的浏覽器判定可以看Tangrame或qwrap,它們基本是IE,webkit,blink內核。

  2.事件的支持偵測

 

  prototype的核心成員kangax寫了一篇文章,來判斷浏覽器對某種事件的支持。裡面給出的實現如下:

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var isEventSupported = (function() { var TAGNAMES = { 'select':'input','change':'input', 'submit':'form','reset':'form', 'error':'img','load':'img','abort':'img' } function isEventSupported(eventName){ var el = document.createElement(TAGNAMES[eventName] || 'div'); eventName = 'on' + eventName; var isSupported = (eventName in el); if (!isSupported) { el.setAttribute(eventName, 'return;'); isSupported = typeof el[eventName] == 'function'; } el = null; return isSupported; } return isEventSupported; })();

  現在jQuery等框架都是使用腳本的簡化版

  不過哪一個也好,這種檢測只對DOM0奏效,像DOMMouseScroll DOMContentLoaded DOMFocusIn DOMFocusOut DOMSubtreeModified DOMNodeInserted DOMNodeRemoved DOMNodeRemovedFromDocument DOMNodeInsertedIntoDocument DOMAttrModified DOMCharactorDataModified這些以DOM開頭的就無能為力了。

  這些事件中,有的非常有用,如DOMMouseScroll,firefox一直不支持mousesheel,只能用它做替代品。

  DOMContentLoaded是實現domReady的重要事件;DOMNodeRemoved是判定元素是否從其父節點移除,父節點可能是其它元素節點或文檔碎片;DOMNodeRemovedFromDocument 是移離DOM樹,DOMAttrModified 以前經常用於模擬IE的onpropertyChange

  css3添加兩種動畫,一種是transition動畫,另外一種是keyframe補間動畫。它們在事件結束時都用事件回調。但在標准化過程中,浏覽器給它們起的名字相當於沒規則。這個也需要預先偵測出來。

 

  下面是bootstrap的實現。聽說來源於modernizr,比較粗糙。比如你使用的Oprera已經支持不帶事件標准事件名。它還是返回oTransitionEnd.

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $.supports.transition = (function(){ var transitionEnd = (function(){ var el = document.createElement('bootstarp'), transEndEventNames = { 'WebkitTransition':'webkitTransitionEnd', 'MozTransition':'transitionend', 'OTransition':'OTransitionEnd otransitionend', 'transition':'transitionend' }; for (var name in transEndEventNames){ if (el.style[name] !== undefined){ return transEndEventNames[name] } } }()); return transitionEnd && { end: transitionEnd } })();

keyframe補間動畫來自mass的fx_neo模塊

? 1 2 3 4 5 6 7 8 9 10 var eventName = { AnimationEvent:'animationend', WebKirAnimationEvent: 'WebKirAnimationEnd' },animationend; for(var name in eventName) { if (/object|function/.test(typeof window[name])){ animationend = eventName[name] break } }

  3.樣式的支持偵探

 

  css3帶來許多好用的樣式,但是麻煩的是每個浏覽器都有自己的私有前綴,massFramework提供了一個cssName方法來處理它們,有就返回可用的駝峰樣式名,沒有就null

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var prefixes = ['','-webkit-','-o-','-moz-','-ms-']; var cssMap = { "float" : $.support.cssFloat ? 'cssFloat' : 'styleFloat',background:'backgroundColor' }; function cssName(name, host, camelCase){ if(cssMap[name]) { return cssMap[name]; } host = host || document.documentElement for (var i = 0 || n = prefixes.length; i < n; i++) { camelCase = $.String.camelize(prefixes[i] + name); if (camelCase in host) { return (cssMap[name] = camelCase) } } return null }

  一個樣式對於N種樣式值,比如display有n種取值,如果要偵測浏覽器是否支持某一種,會很麻煩。為此,浏覽器做了一個善舉,給出一個css.supports的API,如果不支持,則嘗試下一個開源項目。顯然,不是很完美。

  https://github.com/termi/CSS.supports

  4.jQuery的一些常用的特征的含義

  jQuery在support模塊例舉了一些常用的DOM特征支持情況,不過名字起的很怪,不同版本差別也很大,本章以jQuery1.8為准。

  leadingWhitespace:判定浏覽器在進行innerHTML賦值時,是否存在trimLeft操作,這個功能原本是IE發明的,結果其他浏覽器認為要忠於以後的原始值,最前面的空白不能神略掉,要變成一個文本節點,最終IE678返回false,其他浏覽器返回true

  tobody:指在用innerHTML動態創建元素時,浏覽器是否會在table內自動補上tobody,jQuery希望浏覽器別處理,讓jQuery來補全。判斷浏覽器是否只能插入tobody。在表格布局的年代,這個特性十分受用。如果沒有tbody,table會在浏覽器解析到閉合標簽時才顯示出來。如果起始標簽和閉合標簽相隔很遠,換言之,這個表格很長,用戶會什麼都看不到,但有了tbody分段顯示和識別,避免了長時間空白後一下子顯示出來的情況。

   代碼如下:

var div = document.createElement("div");
div.innerHTML = '<table></table>'
alert(div.innerHTML) //=>ie678返回<table><tbody></tbody></table>,其它返回<table></table>

  html.Serialize:判斷浏覽器是否完好支持用innerHTML轉換一個符合html標簽規則的字符串為一個元素節點,此過程jQuery稱為序列化,但IE支持不夠完好。包括scirpt link style mata在內的no-scope元素都轉換失敗

copyright © 萬盛學電腦網 all rights reserved