@demonly
2017-01-23T12:43:36.000000Z
字数 4268
阅读 1307
JavaScript
要优先采用更加通用的方法再考虑客户端检测。
这种方法不检测特定浏览器,只检测其能力。当不具备某项能力时采用其他方法给出解决方案。最常用的判断方法是 if else 语句,此外也可以使用“或”或者使用“!!”来转化为布尔值。
之前的能力检测存在有一个问题,这种方法只能够确定它是否存在,但是并不能够确定它是否是一个函数。因此有人想到了是用 type of 来检测,但是在 IE8 及以前有的函数是通过 COM 对象来实现的,因此在被 typeof 检测时会返回'object'。再加上在 IE 中对于宿主对象的 type of 会返回'unknown'。于是就有了完善的版本。
//作者: Peter Michaux
function isHostMethod(object, property) {
var t = typeof object[property];
return t=='function' ||
(!!(t=='object' && object[property])) ||
t=='unknown';
}
虽然在一些情况下检测是否具备某项能力就可以确定是否为某一个浏览器,但是浏览器是在不断进化的,现在不具备不说明将来也不具备。最好的方法是一次性检测所有需要使用的相关特性。
某些浏览器种可能会存在某种不该出现的 bug,建议在脚本一开始就对这种 bug 进行检查,以便尽早解决问题。
上一章已经提到了关于 useragent 的各种伪装的问题,因此想要检测到究竟是在用哪种浏览器进行访问并不是一件容易的事。
目前的主流引擎有三种,分别是 IE,Gecko,WebKit,KHTML 和IE(现在 Safari 和Opera 都转投了 webkit)。为了减少全局作用域下的多余变量,将引擎和版本的信息封装在一个对象中。同样的下文中的识别系统、设备等也应该以这种形式保存。
var client = function(){
var engine = {
ie: 0,
gecko: 0,
webkit: 0,
ver: null
};
return {
engine: engine
};
}();
在检测到一个引擎之后就将版本号以浮点数的形式写入该引擎对应的值,这样只要转化为布尔值就可以判断是否采用该呈现引擎。但是在引擎对应的值中浮点数会被转化为数值,访问 ver 属性可以获得完整版本信息。
由于 useragent 的伪装问题,引擎的识别必须严格按照顺序,否则会呈现出错误的结果。
if(window.oprea){
engine.ver = window.oprea.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+)||/konqueror\/([^;]+)/).test(ua)){
engine.ver = RegExp["$1"];
engine.KHTML = parseFloat(engine.ver)
}
rv:47.0) Gecko/20100101
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)
}
检测完排版引擎之后很多浏览器就已经知道了,不过新版 Opera、Chrome 和Edge 浏览器都是采用 webkit 引擎,所以需要进一步分辨。
if(/Chrome\/S+/.test(ua)){
browser.ver = Reg["$1"];
browser.chrome = parseFloat(browser.ver)
} else if(/OPR\/S+/.test(ua)){
browser.ver = Reg["$1"];
browser.opera = parseFloat(browser.ver)
} else if(/Version\/S+/.test(ua)){
browser.ver = Reg["$1"];
browser.safari = parseFloat(browser.ver)
} else{
var safariversion = 1;
}
navigator.platform 中保存了平台的信息。
var p = navigator.platform;
system.win = p.indexOf("Win") == 0;
system.mac = p.indexOf("Mac") == 0;
system.xll = (p.indexOf("Xll") == 0) || (p.indexOf("Linux") == 0);
在各个浏览器中对 Windows 操作系统的表示都不相同
windows 版本 | IE4+ | Gecko | Opera | Webkit |
---|---|---|---|---|
95 | “Windows 95” | “Win95” | “Windows 95” | n/a |
98 | “Winodws 98” | “Win98” | “Windows 98” | n/a |
NT 4.0 | “Windows NT” | “WinNT4.0” | “windows NT 4.0” | n/a |
2000 | “Windows NT 5.0” | “Windows NT 5.0” | “Windows NT 5.0” | n/a |
ME | “Win 9x 4.90” | “Win 9x 4.90” | “Win 9x 4.90” | n/a |
XP | “Windows NT 5.1” | “Windows NT 5.1” | “Windows NT 5.1” | “Windows NT 5.1” |
Vista | “Windows NT 6.0” | “Windows NT 6.0” | “Windows NT 6.0” | “Windows NT 6.0” |
7 | “Windows NT 6.1” | “Windows NT 6.1” | “Windows NT 6.1” | “Windows NT 6.1” |
8 | “Windows NT 6.2” | “Windows NT 6.2” | “Windows NT 6.2” | “Windows NT 6.2” |
10 | “Windows NT 10.0” | “Windows NT 10.0” | “Windows NT 10.0” | “Windows NT 10.0” |
if (system.win) {
if (/Win(?:dows )?([^do]{2})\s?(\d+\.\d+)?/i.test(ua)) {
if (RegExp['$1'] == 'NT') {
switch (RegExp['$2']) {
case '5.0': system.win = '2000';
break;
case '5.1': system.win = 'XP';
break;
case '6.0': system.win = 'Vista';
break;
case '6.1': system.win = '7';
break;
case '6.2': system.win = '8';
break;
case '10.0': system.win = '10';
break;
default: system.win = 'NT';
break;
}
} else if (RegExp['$1'] == '9x') {
system.win = 'ME';
} else {
system.win = RegExp['$1'];
}
}
}
对于 iPhone、iPod、iPad,简单地检测就可以了
system.iphone = ua.indexOf('iPhone') > -1;
system.ipod = ua.indexOf('iPod') > -1;
system.ipad = ua.indexOf('iPad') > -1;
此外还可以检测 iOS 版本号,在 iOS3之后 iPad 用户代理字符串为"CPU OS 3_2 like Mac OS X"形式,iPhone 中为"CPU iPhone OS 3_2 like Mac OS X"形式
if (system.mac && ua.indexOf('Mobile') > -1) {
if (/CPU (?:iPhone )?OS (\d+_\d+)/i.test(ua)) {
system.ios = parseFloat(RegExp['$1'].replace('_', '.'));
} else {
system.ios = 2;
}
}
Android 系统也很简单,版本号就跟在 Android 之后
if (/Android (\d+\.\d+)/i.test(ua)) {
ystem.android = parseFloat(RegExp['$1']);
}
诺基亚 N 系列只要检测"NokiaN"就可以了
system.nokiaN = ua.indexOf('NokiaN') > -1;
Windows mobile 系列检测在检测 Windows 系统版本的时候就会被检出,system.win 的值会被设为"CE",而在 Windows Phone7之后由于用户代理字符串中会呈现出"Windows Phone",system.win 的值会被设置为"Ph"。
if (system.win == 'CE') {
system.winMobile = system.win;
} else if (system.win == 'Ph') {
if (/Windows Phone OS (\d+.\d+)/i.test(ua)) {
system.win = 'Phone';
system.winMobile = parseFloat(RegExp['$1']);
}
}
system.wii = ua.indexOf('Wii') > -1;
system.ps = /playstation/i.test(ua);