摘要:用戶代理檢測(cè)用戶代理檢測(cè)是爭(zhēng)議最大的客戶端檢測(cè)技術(shù)。第二個(gè)要檢測(cè)是。由于實(shí)際的版本號(hào)可能會(huì)包含數(shù)字小數(shù)點(diǎn)和字母,所以捕獲組中使用了表示非空格的特殊字符。版本號(hào)不在后面,而是在后面。除了知道設(shè)備,最好還能知道的版本號(hào)。
檢測(cè)Web客戶端的手段很多,各有利弊,但不到萬(wàn)不得已就不要使用客戶端檢測(cè)。只要能找到更通用的方法,就應(yīng)該優(yōu)先采用更通用的方法。一言蔽之,先設(shè)計(jì)最通用的方案,然后再使用特定于瀏覽器的技術(shù)增強(qiáng)方案
能力檢測(cè)能力檢測(cè)(又稱特性檢測(cè)),是廣泛為人接受的客戶端檢測(cè)形式,目標(biāo)不是識(shí)別特定的瀏覽器,而是識(shí)別瀏覽器的能力。
IE5.0之前的版本不支持document.getElementById()這個(gè)DOM方法,盡管可以使用非標(biāo)準(zhǔn)的document.all屬性實(shí)現(xiàn)相同的目的。于是就有類似下面的能力檢測(cè)代碼
function getElement(id) { if (document.getElementById) { return document.getElementById(id); } else if (document.all) { return document.all[id]; } else { throw new Error("No way to retrieve element!"); } }
一個(gè)特性存在,不一定另一個(gè)特性也存在
function getWindowWidth() { if (document.all) { // 假設(shè)這里是IE瀏覽器 return document.documentElement.clientWidth; // 錯(cuò)誤的用法 } else { return window.innerWidth; } }更可靠的能力檢測(cè)
// 這不是能力檢測(cè)——只是檢測(cè)了是否存在相應(yīng)的方法 function isSortable(object) { return !!object.sort; } // 任何包含sort屬性的對(duì)象都會(huì)返回true var result = isSortable({sort: true});
// 這樣更好:檢測(cè)sort是不是函數(shù) function isSortable(object) { return typeof object.sort == "function"; }
在可能的情況下,盡量使用typeof操作符進(jìn)行能力檢測(cè)。特別是,宿主對(duì)象沒有義務(wù)讓typeof返回合理的值。最令人發(fā)指的事就發(fā)生在 IE 中。大多數(shù)瀏覽器在檢測(cè)到document.createElement()存在時(shí),都會(huì)返回true
// 在IE8及之前版本不行 function hasCreateElement() { return typeof document.createElement == "function"; }
IE8- 中這個(gè)函數(shù)返回false,因?yàn)?b>typeof document.createElement返回的的是“object”,而不是“function”。如前所述,DOM對(duì)象是宿主對(duì)象,IE及更早版本中的宿主對(duì)象是通過(guò)COM而非JScript實(shí)現(xiàn)的。因此,document.createElement()函數(shù)確實(shí)是一個(gè)COM對(duì)象。IE9糾正了這個(gè)問(wèn)題,對(duì)所有DOM方法都返回"function"。
能力檢測(cè),不是瀏覽器檢測(cè)// 還不夠具體 var isFirefox = !!(navigator.vendor && navigator.vendorSub); // 假設(shè)過(guò)頭了 var isIE = !!(document.all && document.uniqueID);
檢測(cè)某個(gè)或幾個(gè)屬性并不能夠確定瀏覽器。navigator.vendor和navigator.vendorSub確實(shí)是Firefox的獨(dú)有屬性,但是后來(lái)Safari也依樣畫葫蘆實(shí)現(xiàn)了相同的屬性。document.all && document.uniqueID這兩個(gè)屬性是早期IE的獨(dú)有屬性,目前還存在,但不保證未來(lái)IE不會(huì)去掉。
根據(jù)瀏覽器不同將能力組合起來(lái)是更可取的方式。如果你知道自己的應(yīng)用程序需要使用某些特定的瀏覽器特性,那么最好是一次性檢測(cè)所有相關(guān)特性,而不是分別檢測(cè)。
// 確定瀏覽器是否支持 Netscape風(fēng)格的插件 var hasNSPlugins = !!(navigator.plugins && navigator.plugins.length); // 確定瀏覽器是否具有DOM1級(jí)規(guī)定的能力 var hasDOM1 = !!(document.getElementById && document.createElement && document.getElementsByTagName);
在實(shí)際開發(fā)中,應(yīng)該將能力檢測(cè)作為確定下一步解決方案的依據(jù),而不是用它來(lái)判斷用戶使用的是什么瀏覽器。
怪癖檢測(cè)怪癖檢測(cè) (quirks detection) 的目標(biāo)是識(shí)別瀏覽器的特殊行為。但與能力檢測(cè)不同,怪癖檢測(cè)是想知道瀏覽器存在什么缺陷(也就是bug)。
例如IE8及以前版本存在一個(gè)bug,即如果某個(gè)實(shí)例屬性與[[Enumerbale]]標(biāo)記為false的某個(gè)原型屬性同名,那么該實(shí)例將不會(huì)出現(xiàn)在for-in循環(huán)中。
// 檢測(cè)上述怪癖的代碼 var hasDontEnumQuirk = function() { var o = { toString: function() {} }; for (var prop in o) { if (prop == "toString") { return false; } } return true; }
另一個(gè)經(jīng)常需要檢測(cè)的怪癖是Safari 3 以前版本會(huì)枚舉被隱藏的屬性。
var hasEnumShadowsQuirk = function() { var o = { toString: function() {} }; var count = 0; for (var prop in o) { if (prop == "toString") { count++; } } // 如果瀏覽器存在這個(gè)bug // 就會(huì)返回兩個(gè) toString 的實(shí)例 return (count > 1); }
由于檢測(cè)怪癖涉及運(yùn)行代碼,因此建議僅檢測(cè)那些對(duì)你有直接影響的怪癖,而且最好在腳本一開始就執(zhí)行此類檢測(cè)。
用戶代理檢測(cè)用戶代理檢測(cè)是爭(zhēng)議最大的客戶端檢測(cè)技術(shù)。
用戶代理檢測(cè)通過(guò)用戶代理字符串來(lái)確定實(shí)際使用的瀏覽器。在每一次HTTP請(qǐng)求過(guò)程中,用戶代理字符串是作為響應(yīng)首部發(fā)送的,而且該字符串可以通過(guò)JavaScript的navigator.userAgent屬性訪問(wèn)。
在服務(wù)端,通過(guò)檢測(cè)用戶代理字符串來(lái)確定用戶使用的瀏覽器是一種常用的而且廣為接受的做法。而在客戶端,用戶代理檢測(cè)一般被當(dāng)做一種萬(wàn)不得已采用的做法,其優(yōu)先級(jí)排在能力檢測(cè)和怪癖檢測(cè)之后。
有關(guān)的爭(zhēng)議不得不提電子詐騙(spoofing)。瀏覽器通過(guò)在自己的用戶代理字符串加入一些錯(cuò)誤或誤導(dǎo)信息,來(lái)達(dá)到欺騙服務(wù)器的目的。
用戶代理字符串的歷史略
用戶代理字符串檢測(cè)技術(shù) 識(shí)別呈現(xiàn)引擎確切的紙袋瀏覽器的名字和版本不如確切的紙袋它使用的是什么引擎。
我們要編寫腳本將五大呈現(xiàn)引擎:IE, Gecko, WebKit, KHTML, Opera
為了不在全局作用域中添加多余變量,我們將使用模塊增強(qiáng)模式來(lái)封裝檢測(cè)腳本
var client = function() { var engine = { // 呈現(xiàn)引擎 ie: 0, gecko: 0, webkit: 0, khtml: 0, opera: 0, // 具體的版本號(hào) ver: null }; // 在此檢測(cè)呈現(xiàn)引擎、平臺(tái)和設(shè)備 ... return { engine: engine }; }();
匿名函數(shù)內(nèi)定義了一個(gè)局部變量engin,包含默認(rèn)設(shè)置的對(duì)象字面量,每個(gè)呈現(xiàn)引擎都對(duì)應(yīng)著一個(gè)屬性,默認(rèn)值為0.如果檢測(cè)到了哪個(gè)呈現(xiàn)引擎,那么就以浮點(diǎn)數(shù)值形式,將引擎的版本號(hào)寫入相應(yīng)的屬性。而呈現(xiàn)引擎的完整版本(一個(gè)字符串)則被寫入 ver 屬性。
if (client.engine.ie) { // 如果是IE client.ie 應(yīng)該大于0 ... } else if (client.engine.gecko > 1.5) { if (client.engine.ver === "1.8.1") { // 針對(duì)這個(gè)版本的操作 ... } }
第一個(gè)要檢測(cè)是Opera,我們不相信Opera,是因?yàn)槠溆脩舸碜址粫?huì)將自己標(biāo)識(shí)為Opera。要識(shí)別Opera,必須檢測(cè)window.opera對(duì)象。Opera5+都有這個(gè)版本。在Opera7.6+中調(diào)用version()方法可以返回一個(gè)表示瀏覽器版本的字符串。
if (window.opera) { engine.ver = window.opera.version(); engine.opera = parseFloat(engine.ver); }
第二個(gè)要檢測(cè)是Webkit。因?yàn)閃ebKit用戶代理字符串中包含"Gecko"和"KHTML"這兩個(gè)子字符串,所以如果首先檢測(cè)它們可能會(huì)得出錯(cuò)誤的結(jié)論。不過(guò)“AppleWebKit"是獨(dú)一無(wú)二的。
iPhone 6s Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1
Chrome 74 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36
由于實(shí)際的版本號(hào)可能會(huì)包含數(shù)字、小數(shù)點(diǎn)和字母,所以捕獲組中使用了表示非空格的特殊字符 S 。用戶代理字符串中的版本號(hào)與下一部分的分隔是一個(gè)空格,因此這個(gè)模式可以保證捕獲所有版本信息。
var ua = navigator.userAgent; if (/AppleWebKit/(S+)/.test(ua)) { // S 表示非空格的特殊字符 // S+ 表示不包含空格的子字符串 // 小括號(hào)表示將此子字符串加入捕獲組 // RegExp["$1"] 表示捕獲組的第一個(gè)元素,即為上面描述的子字符串 engine.ver = RegExp["$1"]; engine.webkit = parseFloat(engine.ver); }
接下來(lái)要測(cè)試的是KHTML。同樣,字符串中也包含“Gecko”,因此在排除KHTML之前,我們無(wú)法準(zhǔn)確檢測(cè)基于GECKO的瀏覽器。格式與Webkit差不多。此外由于Konqueror3.1及更早版本中不包含KHTML的版本,故而就要使用Konqueror代替。
if (/KHTML/(S+)/.test(ua) || /Konqueror/([^;]+)/.test(ua)) { engine.ver = RegExp["$1"]; engine.khtml = parseFloat(engine.ver); }
下面檢測(cè)Gecko。版本號(hào)不在Gecko后面,而是在 “rv:”后面。比如WindowsXP 下的Firefox2.0.0.11:Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11
// 在上面的字符串中實(shí)際匹配的是"rv:1.8.1.11) Gecko/20071127" // gecko的版本號(hào)位于 rv: 與一個(gè)閉括號(hào)之間,因此為了提取出這個(gè)版本號(hào) // [^)]+ 就是將 rv: 之后的字符串排除 ) 閉括號(hào) 之后加入捕獲組 // 正則表達(dá)式要查找所有不是閉括號(hào)的字符,還要查找字符串"Gecko/"后跟8個(gè)數(shù)字 if (/rv:([^)]+)) Gecko/d{8}/.test(ua)) { engine.ver = RegExp["$1"]; engine.gecko = parseFloat(engine.ver); }
最后一個(gè)檢測(cè)IE。IE的版本號(hào)位于字符串"MSIE"的后面、一個(gè)分號(hào)的前面
// 五個(gè)呈現(xiàn)引擎完整的檢測(cè)代碼如下 var ua = navigator.userAgent; if (window.opera) { engine.ver = window.opera.version(); engine.opera = parseFloat(engine.ver); } else if (/AppleWebKit/(S+)/.test(ua)) { engine.ver = RegExp["$1"]; engine.webkit = parseFloat(engine.ver); } else if (/KHTML/(S+)/.test(ua) || /Konqueror/([^;]+)/.test(ua)) { engine.ver = RegExp["$1"]; engine.khtml = parseFloat(engine.ver); } else if (/rv:([^)]+)) Gecko/d{8}/.test(ua)) { engine.ver = RegExp["$1"]; engine.gecko = parseFloat(engine.ver); } else if (/MSIE ([^;]+)/.test(ua)) { engine.ver = RegExp["$1"]; engine.ie = parseFloat(engine.ver); }識(shí)別瀏覽器
識(shí)別呈現(xiàn)引擎大多數(shù)情況下足以為我們采取正確的操作提供了依據(jù)(pc上,移動(dòng)端大部分都不行)。
蘋果公司的Safari瀏覽器和谷歌的Chrome瀏覽器都是用Webkit作為呈現(xiàn)引擎,但它們的JavaScript引擎卻不同。
// 我們的檢測(cè)代碼需要添加瀏覽器的檢測(cè) var client = function() { var engine = { // 呈現(xiàn)引擎 ie: 0, gecko: 0, webkit: 0, khtml: 0, opera: 0, // 具體的版本號(hào) ver: null }; var browser = { // 瀏覽器 ie: 0, firefox: 0, safari: 0, konq: 0, opera: 0, chrome: 0, // 具體的版本號(hào) ver: null } // 在此檢測(cè)呈現(xiàn)引擎、平臺(tái)和設(shè)備 ... return { engine: engine, browser: browser }; }();
由于大多數(shù)瀏覽器與其呈現(xiàn)引擎密切相關(guān),所以下面的檢測(cè)瀏覽器代碼和檢測(cè)呈現(xiàn)引擎的代碼是混合在一起的。
var ua = navigator.userAgent; if (window.opera) { engine.ver = browser.ver = window.opera.version(); engine.opera = browser.opera = parseFloat(engine.ver); } else if (/AppleWebKit/(S+)/.test(ua)) { engine.ver = RegExp["$1"]; engine.webkit = parseFloat(engine.ver); // 確定是Chrome還是Safari if (/Chrome/(S+)/.test(ua)) { browser.ver = RegExp["$1"]; browser.chrome = parseFloat(browser.ver); } else if (/Version/(S+)/.test(ua)) { browser.ver = RegExp["$1"]; browser.safari = parseFloat(browser.ver); } else { // 近似的確定版本號(hào) var safariVersion = 1; if (engine.webkit < 100) { safariVersion = 1; } else if (engine.webkit < 312) { safariVersion = 1.2; } else if (engine.webkit < 412) { safariVersion = 1.3; } else { safariVersion = 2; } browser.safari = browser.ver = safariVersion; } } else if (/KHTML/(S+)/.test(ua) || /Konqueror/([^;]+)/.test(ua)) { engine.ver = browser.ver = RegExp["$1"]; engine.khtml = browser.konq = parseFloat(engine.ver); } else if (/rv:([^)]+)) Gecko/d{8}/.test(ua)) { engine.ver = RegExp["$1"]; engine.gecko = parseFloat(engine.ver); // 確定是不是Firefox瀏覽器 if (/Firefox/(S+)/.test(ua)) { browser.ver = RegExp["$1"]; browser.firefox = parseFloat(browser.ver); } } else if (/MSIE ([^;]+)/.test(ua)) { engine.ver = RegExp["$1"]; engine.ie = parseFloat(engine.ver); }
有了上述代碼之后,我們就可以編寫以下邏輯
if (client.engine.webkit) { if (client.browser.chrome) { // 執(zhí)行針對(duì)Chrome的代碼 } else if (client.browser.safari) { // 執(zhí)行針對(duì)Safari的代碼 } } else if (client.engine.gecko) { if(client。browser.Firefox) { // 執(zhí)行針對(duì)Firefox的代碼 } else { // 執(zhí)行針對(duì)其他Gecko瀏覽器代碼 } }識(shí)別平臺(tái)
瀏覽器針對(duì)不同平臺(tái)會(huì)有不同的版本,如Safari Firefox Opera , 在不同平臺(tái)下可能會(huì)有不同問(wèn)題。目前三大主流平臺(tái)是 Window/Mac/Unix(包括各種Linux)。
// 我們的檢測(cè)代碼需要添加平臺(tái)的檢測(cè) var client = function() { var engine = { // 呈現(xiàn)引擎 ie: 0, gecko: 0, webkit: 0, khtml: 0, opera: 0, // 具體的版本號(hào) ver: null }; var browser = { // 瀏覽器 ie: 0, firefox: 0, safari: 0, konq: 0, opera: 0, chrome: 0, // 具體的版本號(hào) ver: null } var system = { win: false, mac: false, // Unix x11: false } // 在此檢測(cè)呈現(xiàn)引擎、平臺(tái)和設(shè)備 ... return { engine: engine, browser: browser, system: system }; }();
檢測(cè)navigator.platform來(lái)確定平臺(tái),在不同瀏覽器中給出的值都是一致的,檢測(cè)起來(lái)非常直觀
var p = navigator.platform; // window 可能有 Win32 和 Win64 system.win = p.indexOf("Win") == 0; system.win = p.indexOf("Mac") == 0; system.win = (p.indexOf("U11") == 0) || (p.indexOf("Linux") == 0);識(shí)別Windows系統(tǒng)
在WindowsXP之前,Windows有分別針對(duì)家庭和商業(yè)用戶的兩個(gè)版本。針對(duì)家庭的分別是Windows95和WindowsME。針對(duì)商業(yè)的一直叫WindowsNT,最后由于市場(chǎng)原因改名為Windows2000。這兩個(gè)產(chǎn)品線后來(lái)又合并成一個(gè)由WindowsNT發(fā)展而來(lái)的公共代碼基,代表產(chǎn)品就是WindowsXP。
原著編撰年代較早(2012.3),筆記這里只列舉WindowsXP以后的代碼,并補(bǔ)充Windows10
版本 | IE 4+ | Gecko | Opera < 7 | Opera 7+ | WebKit |
---|---|---|---|---|---|
XP | "Windows NT 5.1" | "Windows NT 5.1" | "WindowsXP" | "Windows NT 5.1" | "Windows NT 5.1" |
Vista | "Windows NT 6.0" | "Windows NT 6.0" | n/a | "Windows NT 6.0" | "Windows NT 6.0" |
7 | "Windows NT 6.1" | "Windows NT 6.1" | n/a | "Windows NT 6.1" | "Windows NT 6.1" |
10 | "Windows NT 10.0" | "Windows NT 10.0" | n/a | "Windows NT 10.0" | "Windows NT 10.0" |
忽略掉Opera 7- 的用戶和WindowsXP以前的系統(tǒng),將原著代碼修改如下:
if (system.win) { // 比如在Windows10的Chrome里,userAgent返回字符串 // Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... // 我們要提取兩個(gè)子字符串 "NT" 和 "10.0" // ([^dows]{2}) 表示排除包含"dows"的字符之后的后2位字符 加入捕獲組 $1 // (d+.d+) 表示 x.x(x) 形式的版本號(hào)加入捕獲組 $2 if (/Windows ([^dows]{2})s?(d+.d+)?/.test(ua)) { if (RegExp["$1"] == "NT") { switch (RegExp["$2"]) { case "5.1": system.win = "XP"; break; case "6.0": system.win = "Vista"; break; case "6.1": system.win = "7"; break; case "10.0": system.win = "10"; break; default: system.win = "NT"; break; } } else { system.win = RegExp["$1"]; } } }識(shí)別移動(dòng)設(shè)備
// 我們?cè)谙到y(tǒng)變量里添加移動(dòng)設(shè)備的屬性 var client = function() { ... var system = { win: false, mac: false, // Unix x11: false, // 移動(dòng)設(shè)備 iphone: false, ipod: false, ipad: false, ios: false, android: false, nokiaN: false, winMobile: false } // 在此檢測(cè)呈現(xiàn)引擎、平臺(tái)和設(shè)備 ... return { engine: engine, browser: browser, system: system }; }();
通常的檢測(cè)字符串"iphone", "ipod", "ipad", 就可以分別設(shè)置相應(yīng)屬性的值了。
system.iphone = ua.indexOf("iPhone") > -1; system.ipod = ua.indexOf("iPod") > -1; system.ipad = ua.indexOf("iPad") > -1;
除了知道iOS設(shè)備,最好還能知道iOS的版本號(hào)。在iOS3之前,用戶代理字符串只包含"CPU like Mac OS",后來(lái)iPhone中又改成"CPU iPhone OS 3_0 like Mac OS X",iPad中又改成"CPU OS 3_2 like Mac OS X"。
檢查系統(tǒng)是不是 Mac OS、字符串中是否存在"Mobile",可以保證不論是什么版本,system.ios中都不會(huì)是 0
// 檢測(cè)iOS版本 if (system.max && ua.indexOf("Mobile") > -1) { if (/CPU (?:iPhone )?OS (d+_d+)/.test(ua)) { system.ios = parseFloat(RegExp.$1.repalce("_", ".")); } else { system.ios = 2; // 不能準(zhǔn)確判斷只能靠猜 } }
檢測(cè)Android操作系統(tǒng)也很簡(jiǎn)單,搜索字符串"Android"并取得緊跟其后的版本號(hào)
// 檢測(cè)Android版本 if (/Android (d+.d+)/.test(ua)) { system.android = parseFloat(RegExp.$1); }
遠(yuǎn)在天國(guó)的諾基亞,略
在天國(guó)門口的Windows Phone , 略
識(shí)別游戲系統(tǒng)除了移動(dòng)設(shè)備之外,視頻游戲系統(tǒng)中的Web瀏覽器也開始日益普及。任天堂Wii和PlayStation3+等等。
Wii的瀏覽器實(shí)際上是定制版的Opera,專門為Wii Remote設(shè)計(jì)的。用戶代理字符串:Opera/9.10 (Nintendo Wii;U; ; 1621; en)
PlayStation的瀏覽器是自己開發(fā)的,沒有基于前面提到的任何呈現(xiàn)引擎。用戶代理字符串:Mozilla/5.0 (PLAYSTATION 3; 2.00)
// 我們?cè)谙到y(tǒng)變量里添加游戲設(shè)備的屬性 var client = function() { ... var system = { ... // 游戲系統(tǒng) wii: false, ps: false } // 在此檢測(cè)呈現(xiàn)引擎、平臺(tái)和設(shè)備 ... return { engine: engine, browser: browser, system: system }; }();
檢測(cè)前述游戲系統(tǒng)的代碼如下
system.wii = ua.indexOf("Wii") > -1; // ps要忽略大小寫 system.ps = /playstation/i.test(ua);完整的代碼
// 個(gè)人做了部分修改 修改時(shí)間 2019.5.17 var client = function() { var engine = { // 呈現(xiàn)引擎 ie: 0, gecko: 0, webkit: 0, khtml: 0, opera: 0, // 具體的版本號(hào) ver: null }; var browser = { // 瀏覽器 ie: 0, firefox: 0, safari: 0, konq: 0, opera: 0, chrome: 0, // 具體的版本號(hào) ver: null } var system = { win: false, mac: false, // Unix x11: false, // 移動(dòng)設(shè)備 iphone: false, ipod: false, ipad: false, ios: false, android: false, nokiaN: false, winMobile: false, // 游戲系統(tǒng) wii: false, ps: false } // 在此檢測(cè)呈現(xiàn)引擎、平臺(tái)和設(shè)備 var ua = navigator.userAgent; if (window.opera) { engine.ver = browser.ver = window.opera.version(); engine.opera = browser.opera = parseFloat(engine.ver); } else if (/AppleWebKit/(S+)/.test(ua)) { engine.ver = RegExp["$1"]; engine.webkit = parseFloat(engine.ver); // 確定是Chrome還是Safari if (/Chrome/(S+)/.test(ua)) { browser.ver = RegExp["$1"]; browser.chrome = parseFloat(browser.ver); } else if (/Version/(S+)/.test(ua)) { browser.ver = RegExp["$1"]; browser.safari = parseFloat(browser.ver); } else { // 近似的確定版本號(hào) var safariVersion = 1; if (engine.webkit < 100) { safariVersion = 1; } else if (engine.webkit < 312) { safariVersion = 1.2; } else if (engine.webkit < 412) { safariVersion = 1.3; } else { safariVersion = 2; } browser.safari = browser.ver = safariVersion; } } else if (/KHTML/(S+)/.test(ua) || /Konqueror/([^;]+)/.test(ua)) { engine.ver = browser.ver = RegExp["$1"]; engine.khtml = browser.konq = parseFloat(engine.ver); } else if (/rv:([^)]+)) Gecko/d{8}/.test(ua)) { engine.ver = RegExp["$1"]; engine.gecko = parseFloat(engine.ver); // 確定是不是Firefox瀏覽器 if (/Firefox/(S+)/.test(ua)) { browser.ver = RegExp["$1"]; browser.firefox = parseFloat(browser.ver); } } else if (/MSIE ([^;]+)/.test(ua)) { engine.ver = RegExp["$1"]; engine.ie = parseFloat(engine.ver); } // 檢測(cè)瀏覽器 browser.ie = engine.ie; browser.opera = engine.opera; // 檢測(cè)平臺(tái) var p = navigator.platform; system.win = p.indexOf("Win") == 0; system.win = p.indexOf("Mac") == 0; system.win = (p.indexOf("U11") == 0) || (p.indexOf("Linux") == 0); // 檢測(cè)Windos操作系統(tǒng) // 排除WindosXP以前的系統(tǒng) if (system.win) { if (/Windows ([^dows]{2})s?(d+.d+)?/.test(ua)) { if (RegExp["$1"] == "NT") { switch (RegExp["$2"]) { case "5.1": system.win = "XP"; break; case "6.0": system.win = "Vista"; break; case "6.1": system.win = "7"; break; case "10.0": system.win = "10"; break; default: system.win = "NT"; break; } } else { system.win = RegExp["$1"]; } } } // 移動(dòng)設(shè)備 // 剔除了諾基亞和windows phone system.iphone = ua.indexOf("iPhone") > -1; system.ipod = ua.indexOf("iPod") > -1; system.ipad = ua.indexOf("iPad") > -1; // 檢測(cè)iOS版本 if (system.max && ua.indexOf("Mobile") > -1) { if (/CPU (?:iPhone )?OS (d+_d+)/.test(ua)) { system.ios = parseFloat(RegExp.$1.repalce("_", ".")); } else { system.ios = 2; // 不能準(zhǔn)確判斷只能靠猜 } } // 檢測(cè)Android版本 if (/Android (d+.d+)/.test(ua)) { system.android = parseFloat(RegExp.$1); } // 游戲系統(tǒng) system.wii = ua.indexOf("Wii") > -1; system.ps = /playstation/i.test(ua); return { engine: engine, browser: browser, system: system }; }();使用方法
用戶代理檢測(cè)是客戶端檢測(cè)的最后一個(gè)選項(xiàng)。只要可能,都應(yīng)該優(yōu)先采用能力檢測(cè)和怪癖檢測(cè)。用戶代理檢測(cè)一般適用于下列情形:
不能直接準(zhǔn)確的使用能力檢測(cè)或怪癖檢測(cè)。例如某些瀏覽器實(shí)現(xiàn)了為將來(lái)功能預(yù)留的存根函數(shù)(stub)。在這種情況下,僅測(cè)試相應(yīng)的函數(shù)是否存在還得不到足夠信息。
同一款瀏覽器在不同平臺(tái)下具備不同的能力。
為了跟蹤分析等目的需要知道確切的瀏覽器。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/109582.html
摘要:具體說(shuō)就是執(zhí)行流進(jìn)入下列任何一個(gè)語(yǔ)句時(shí),作用域鏈就會(huì)得到加長(zhǎng)語(yǔ)句的塊。如果局部環(huán)境中存在著同名的標(biāo)識(shí)符,就不會(huì)使用位于父環(huán)境中的標(biāo)識(shí)符訪問(wèn)局部變量要比訪問(wèn)全局變量更快,因?yàn)椴挥孟蛏纤阉髯饔糜蜴湣? 基本類型和引用類型的值 ECMAscript變量包含 基本類型值和引用類型值 基本類型值值的是基本數(shù)據(jù)類型:Undefined, Null, Boolean, Number, String ...
摘要:僅限數(shù)值表示新窗口的高度。此時(shí)只要檢查這個(gè)返回值就可以確定彈窗是否被屏蔽。返回一個(gè)布爾值,代表用戶選擇還是返回一個(gè)字符串或者,輸入了值并確定,返回字符串,其他方法關(guān)閉返回打印查找對(duì)話框。 ECMAScript是JavaScript的核心,但如果要在Web中使用JavaScript,那么BOM(瀏覽器對(duì)象模型)則無(wú)疑才是真正的核心。 W3C為了把瀏覽器中JavaScript最基本的部分...
摘要:表示應(yīng)該立即下載腳本,但不應(yīng)妨礙頁(yè)面中的其他操作可選。表示通過(guò)屬性指定的代碼的字符集。表示腳本可以延遲到文檔完全被解析和顯示之后再執(zhí)行。實(shí)際上,服務(wù)器在傳送文件時(shí)使用的類型通常是,但在中設(shè)置這個(gè)值卻可能導(dǎo)致腳本被忽略。 第1章 JavaScript 簡(jiǎn)介 雖然JavaScript和ECMAScript通常被人們用來(lái)表達(dá)相同的含義,但JavaScript的含義比ECMA-262要多得多...
摘要:本質(zhì)上是由一組無(wú)序名值對(duì)組成的。浮點(diǎn)數(shù)值的最高精度是位小數(shù),但在進(jìn)行計(jì)算時(shí)其精度遠(yuǎn)遠(yuǎn)不如證書。例如這是使用基于數(shù)值的浮點(diǎn)計(jì)算的通病,并非獨(dú)此一家數(shù)值范圍。 函數(shù)名不能使用關(guān)鍵字(typeof不行但typeOf可以,區(qū)分大小寫) 標(biāo)識(shí)符就是指變量、函數(shù)、屬性的名字,或者函數(shù)的參數(shù)。 第一個(gè)字符必須是一個(gè)字母、下劃線(_)或者一個(gè)美元符號(hào)($) 其他字符可以是字母、下劃線、美元符號(hào)或...
摘要:對(duì)的兩個(gè)主要拓展是選擇和。以下插入標(biāo)記的拓展已經(jīng)納入了規(guī)范。在寫模式下,會(huì)根據(jù)指定的字符串創(chuàng)建新的子樹,然后用這個(gè)子樹完全替換調(diào)用元素。在刪除帶有時(shí)間處理程序或引用了其他對(duì)象子樹時(shí),就有可能導(dǎo)致內(nèi)存占用問(wèn)題。 盡管DOM作為API已經(jīng)非常完善了,但為了實(shí)現(xiàn)更多功能,仍然會(huì)有一些標(biāo)準(zhǔn)或?qū)S械耐卣埂?008年之前,瀏覽器中幾乎所有的拓展都是專有的,此后W3C著手將一些已經(jīng)成為事實(shí)標(biāo)準(zhǔn)的專...
閱讀 2305·2021-09-27 13:35
閱讀 586·2019-08-30 15:55
閱讀 838·2019-08-30 15:53
閱讀 581·2019-08-30 15:52
閱讀 2177·2019-08-30 12:59
閱讀 2300·2019-08-29 16:42
閱讀 1485·2019-08-26 18:26
閱讀 2499·2019-08-26 13:48