javaScript 浏览器检测
浏览器检测
学习要点:
1.navigator 对象
2.客户端检测
由于每个浏览器都具有自己独到的扩展,所以在开发阶段来判断浏览器是一个非常重要的步骤。虽然浏览器开发商在公共接口方面投入了很多精力,努力的去支持最常用的公共功能;但在现实中,浏览器之间的差异,以及不同浏览器的“怪癖”却是非常多的,因此客户端检测除了是一种补救措施,更是一种行之有效的开发策略。
一.navigator对象
navigator 对象最早由Netscape Navigator2.0 引入的navigator 对象,现在已经成为识别客户端浏览器的事实标准。与之前的BOM 对象一样,每个浏览器中的navigator 对象也都有一套自己的属性。
1.浏览器及版本号
不同的浏览器支持的功能、属性和方法各有不同。比如IE 和Firefox 显示的页面可能就会有所略微不同。
alert('浏览器名称:' + navigator.appName);
alert('浏览器版本:' + navigator.appVersion);
alert('浏览器用户代理字符串:' + navigator.userAgent);
alert('浏览器所在的系统:' + navigator.platform);
2.浏览器嗅探器
浏览器嗅探器是一段程序,有了它,浏览器检测就变得简单了。我们这里提供了一个browserdetect.js 文件,用于判断浏览器的名称、版本号及操作系统。
//browserdetect.js 文件
1 var BrowserDetect = { 2 init: function () { 3 this.browser = this.searchString(this.dataBrowser) || "An unknown browser"; 4 this.version = this.searchVersion(navigator.userAgent) 5 || this.searchVersion(navigator.appVersion) 6 || "an unknown version"; 7 this.OS = this.searchString(this.dataOS) || "an unknown OS"; 8 }, 9 searchString: function (data) { 10 for (var i=0;i<data.length;i++) { 11 var dataString = data[i].string; 12 var dataProp = data[i].prop; 13 this.versionSearchString = data[i].versionSearch || data[i].identity; 14 if (dataString) { 15 if (dataString.indexOf(data[i].subString) != -1) 16 return data[i].identity; 17 } 18 else if (dataProp) 19 return data[i].identity; 20 } 21 }, 22 searchVersion: function (dataString) { 23 var index = dataString.indexOf(this.versionSearchString); 24 if (index == -1) return; 25 return parseFloat(dataString.substring(index+this.versionSearchString.length+1)); 26 }, 27 dataBrowser: [ 28 { 29 string: navigator.userAgent, 30 subString: "Chrome", 31 identity: "Chrome" 32 }, 33 { string: navigator.userAgent, 34 subString: "OmniWeb", 35 versionSearch: "OmniWeb/", 36 identity: "OmniWeb" 37 }, 38 { 39 string: navigator.vendor, 40 subString: "Apple", 41 identity: "Safari", 42 versionSearch: "Version" 43 }, 44 { 45 prop: window.opera, 46 identity: "Opera" 47 }, 48 { 49 string: navigator.vendor, 50 subString: "iCab", 51 identity: "iCab" 52 }, 53 { 54 string: navigator.vendor, 55 subString: "KDE", 56 identity: "Konqueror" 57 }, 58 { 59 string: navigator.userAgent, 60 subString: "Firefox", 61 identity: "Firefox" 62 }, 63 { 64 string: navigator.vendor, 65 subString: "Camino", 66 identity: "Camino" 67 }, 68 { // for newer Netscapes (6+) 69 string: navigator.userAgent, 70 subString: "Netscape", 71 identity: "Netscape" 72 }, 73 { 74 string: navigator.userAgent, 75 subString: "MSIE", 76 identity: "Internet Explorer", 77 versionSearch: "MSIE" 78 }, 79 { 80 string: navigator.userAgent, 81 subString: "Gecko", 82 identity: "Mozilla", 83 versionSearch: "rv" 84 }, 85 { // for older Netscapes (4-) 86 string: navigator.userAgent, 87 subString: "Mozilla", 88 identity: "Netscape", 89 versionSearch: "Mozilla" 90 } 91 ], 92 dataOS : [ 93 { 94 string: navigator.platform, 95 subString: "Win", 96 identity: "Windows" 97 }, 98 { 99 string: navigator.platform, 100 subString: "Mac", 101 identity: "Mac" 102 }, 103 { 104 string: navigator.userAgent, 105 subString: "iPhone", 106 identity: "iPhone/iPod" 107 }, 108 { 109 string: navigator.platform, 110 subString: "Linux", 111 identity: "Linux" 112 } 113 ] 114 115 }; 116 BrowserDetect.init();
调用方式 说明
BrowserDetect.browser 浏览器的名称,例如Firefox,IE
BrowserDetect.version 浏览器的版本,比如,7、11
BrowserDetect.OS 浏览器所宿主的操作系统,比如Windows、Linux
alert(BrowserDetect.browser); //名称
alert(BrowserDetect.version); //版本
alert(BrowserDetect.OS) //系统
3.检测插件
插件是一类特殊的程序。他可以扩展浏览器的功能,通过下载安装完成。比如,在线音乐、视频动画等等插件。navigator 对象的plugins 属性,这个一个数组。存储在浏览器已安装插件的完整列表。
属性 含义
name 插件名
filename 插件的磁盘文件名
length plugins 数组的元素个数
description 插件的描述信息
//列出所有的插件名
1 for (var i = 0; i < navigator.plugins.length; i ++) { 2 3 document.write(navigator.plugins[i].name + '<br />'); 4 5 } 6 7 //检测非IE 浏览器插件是否存在 8 9 function hasPlugin(name) { 10 11 var name = name.toLowerCase(); 12 13 for (var i = 0; i < navigator.plugins.length; i ++) { 14 15 if (navigator.plugins[i].name.toLowerCase().indexOf(name) > -1) { 16 17 return true; 18 19 } 20 21 } 22 23 return false; 24 25 } 26 27 alert(hasPlugin('Flash')); //检测Flash 是否存在 28 29 alert(hasPlugin('java')) //检测Java 是否存在
4.ActiveX
IE 浏览器没有插件,但提供了ActiveX 控件。ActiveX 控件一种在Web 页面中嵌入对象或组件的方法。由于在JS 中,我们无法把所有已安装的ActiveX 控件遍历出来,但我们还是可以去验证是否安装了此控件。
1 //检测IE 中的控件 2 3 function hasIEPlugin(name) { 4 5 try { 6 7 new ActiveXObject(name); 8 9 return true; 10 11 } catch (e) { 12 13 return false; 14 15 } 16 17 } 18 19 //检测Flash 20 21 alert(hasIEPlugin('ShockwaveFlash.ShockwaveFlash')); 22 23 24 25 PS:ShockwaveFlash.ShockwaveFlash 是IE 中代表FLASH 的标识符,你需要检查哪种 26 27 控件,必须先获取它的标识符。 28 29 30 31 //跨浏览器检测是否支持Flash 32 33 function hasFlash() { 34 35 var result = hasPlugin('Flash'); 36 37 if (!result) { 38 39 result = hasIEPlugin('ShockwaveFlash.ShockwaveFlash'); 40 41 } 42 43 return result; 44 45 } 46 47 //检测Flash 48 49 alert(hasFlash());
5.MIME 类型
MIME 是指多用途因特网邮件扩展。它是通过因特网发送邮件消息的标准格式。现在也被用于在因特网中交换各种类型的文件。
PS:mimeType[]数组在IE 中不产生输出。
mimeType 对象的属性
属性 含义
type MIME 类型名
description MIME 类型的描述信息
enabledPlugin 指定MIME 类型配置好的plugin 对象引用
suffixes MIME 类型所有可能的文件扩展名
1 //遍历非IE 下所有MIME 类型信息 2 3 for (var i = 0; i < navigator.mimeTypes.length; i++) { 4 5 if (navigator.mimeTypes[i].enabledPlugin != null) { 6 7 document.write('<dl>'); 8 9 document.write('<dd>类型名称:' + navigator.mimeTypes[i].type + '</dd>'); 10 11 document.write('<dd>类型引用:' + navigator.mimeTypes[i].enabledPlugin.name +'</dd>'); 12 13 document.write('<dd>类型描述:' + navigator.mimeTypes[i].description + '</dd>'); 14 15 document.write('<dd>类型后缀:' + navigator.mimeTypes[i].suffixes + '</dd>'); 16 17 document.write('</dl>') 18 19 } 20 21 }
二.客户端检测
客户端检测一共分为三种,分别为:能力检测、怪癖检测和用户代理检测,通过这三种检测方案,我们可以充分的了解当前浏览器所处系统、所支持的语法、所具有的特殊性能。
1.能力检测
能力检测又称作为特性检测,检测的目标不是识别特定的浏览器,而是识别浏览器的能力。能力检测不必估计特定的浏览器,只需要确定当前的浏览器是否支持特定的能力,就可以给出可行的解决方案。
//BOM 章节的一段程序 var width = window.innerWidth; //如果是非IE 浏览器 if (typeof width != 'number') { //如果是IE,就使用document if (document.compatMode == 'CSS1Compat') { width = document.documentElement.clientWidth; } else { width = document.body.clientWidth; //非标准模式使用body } }
PS:上面其实有两块地方使用了能力检测,第一个就是是否支持innerWidth 的检测,第二个就是是否是标准模式的检测,这两个都是能力检测。
2.怪癖检测(bug 检测)
与能力检测类似,怪癖检测的目标是识别浏览器的特殊行为。但与能力检测确认浏览器支持什么能力不同,怪癖检测是想要知道浏览器存在什么缺陷(bug)。bug 一般属于个别浏览器独有,在大多数新版本的浏览器被修复。在后续的开发过程中,如果遇到浏览器bug 我们再详细探讨。
var box = {
toString : function () {} //创建一个toString(),和原型中重名了
};
for (var o in box) {
alert(o); //IE 浏览器的一个bug,不识别了
}
3.用户代理检测
用户代理检测通过检测用户代理字符串来确定实际使用的浏览器。在每一次HTTP 请求过程中,用户代理字符串是作为响应首部发送的,而且该字符串可以通过JavaScript 的navigator.userAgent 属性访问。用户代理代理检测,主要通过navigator.userAgent 来获取用户代理字符串的,通过这组字符串,我们来获取当前浏览器的版本号、浏览器名称、系统名称。
PS:在服务器端,通过检测用户代理字符串确定用户使用的浏览器是一种比较广为接受的做法。但在客户端,这种测试被当作是一种万不得已的做法,且饱受争议,其优先级排在能力检测或怪癖检测之后。饱受争议的原因,是因为它具有一定的欺骗性。
1 document.write(navigator.userAgent); //得到用户代理字符串 2 3 Firefox14.0.1 4 5 Mozilla/5.0 (Windows NT 5.1; rv:14.0) Gecko/20100101 Firefox/14.0.1 6 7 Firefox3.6.28 8 9 Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.28) Gecko/20120306 10 11 Firefox/3.6.28 12 13 Chrome20.0.1132.57 m 14 15 Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.11 (KHTML, like Gecko) 16 17 Chrome/20.0.1132.57 Safari/536.11 18 19 Safari5.1.7 20 21 Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 22 23 Safari/534.57.2 24 25 IE7.0 26 27 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 28 29 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) 30 31 IE8.0 32 33 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 34 35 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) 36 37 IE6.0 38 39 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 40 41 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) 42 43 Opera12.0 44 45 Opera/9.80 (Windows NT 5.1; U; zh-cn) Presto/2.10.289 Version/12.00 46 47 Opera7.54 48 49 Opera/7.54 (Windows NT 5.1; U) [en] 50 51 Opera8 52 53 Opera/8.0 (Window NT 5.1; U; en) 54 55 Konqueror (Linux 集成,基于KHTML 呈现引擎的浏览器) 56 57 Mozilla/5.0 (compatible; Konqueror/3.5; SunOS) KHTML/3.5.0 (like Gecko)
只要仔细的阅读这些字符串,我们可以发现,这些字符串包含了浏览器的名称、版本和所宿主的操作系统。每个浏览器有它自己的呈现引擎:所谓呈现引擎,就是用来排版网页和解释浏览器的引擎。通过代理字符串发现,我们归纳出浏览器对应的引擎:
IE -- Trident, IE8 体现出来了,之前的未体现
Firefox -- Gecko,
Opera -- Presto, 旧版本根本无法体现呈现引擎
Chrome -- WebKit WebKit 是KHTML 呈现引擎的一个分支,后独立开来
Safari -- WebKit
Konqueror -- KHTML
由上面的情况,我们需要检测呈现引擎可以分为五大类:IE、Gecko、WebKit、KHTML和Opera。
var client = function () { //创建一个对象 var engine = { //呈现引擎 ie : false, gecko : false, webkit : false, khtml : false, opera : false, ver : 0 //具体的版本号 }; return { engine : engine //返回呈现引擎对象 }; }(); //自我执行 alert(client.engine.ie); //获取ie
以上的代码实现了五大引擎的初始化工作,分别给予true 的初值,并且设置版本号为0。下面我们首先要做的是判断Opera,因为Opera 浏览器支持window.opera 对象,通过这个对象,我们可以很容易获取到Opera 的信息。
for (var p in window.opera) { //获取window.opera 对象信息
document.write(p + "<br />");
}
if (window.opera) { //判断opera 浏览器
engine.ver = window.opera.version(); //获取opera 呈现引擎版本
engine.opera = true; //设置真
}
接下来,我们通过正则表达式来获取WebKit 引擎和它的版本号。
else if (/AppleWebKit\/(\S+)/.test(ua)) { //正则WebKit
engine.ver = RegExp['$1']; //获取WebKit 版本号
engine.webkit = true;
}
然后,我们通过正则表达式来获取KHTML 引擎和它的版本号。由于这款浏览器基于Linux,我们无法测试。
//获取KHTML 和它的版本号
else if (/KHTML\/(\S+)/.test(ua) || /Konqueror\/([^;]+)/.test(ua)) {
engine.ver = RegExp['$1'];
engine.khtml = true;
}
下面,我们通过正则表达式来获取Gecko 引擎和它的版本号。
else if (/rv:([^\)]+)\) Gecko\/\d{8}/.test(ua)) { //获取Gecko 和它的版本号
engine.ver = RegExp['$1'];
engine.gecko = true;
}
最后,我们通过正则表达式来获取IE 的引擎和它的版本号。因为IE8 之前没有呈现引擎,所以,我们只有通过"MSIE"这个共有的字符串来获取。
else if (/MSIE ([^;]+)/.test(ua)) { //获取IE 和它的版本号
engine.ver = RegExp['$1'];
engine.ie = true;
}
上面获取各个浏览器的引擎和引擎的版本号,但大家也发现了,其实有些确实是浏览器的版本号。所以,下面,我们需要进行浏览器名称的获取和浏览器版本号的获取。
根据目前的浏览器市场份额,我们可以给一下浏览器做检测:IE、Firefox、konq、opera、chrome、safari。
var browser = { //浏览器对象 ie : false, firefox : false, konq : false, opera : false, chrome : false, safari : false, ver : 0, //具体版本 name : '' //具体的浏览器名称 };
对于获取IE 浏览器的名称和版本,可以直接如下:
else if (/MSIE ([^;]+)/.test(ua)) {
engine.ver = browser.ver = RegExp['$1']; //设置版本
engine.ie = browser.ie = true; //填充保证为true
browser.name = 'Internet Explorer'; //设置名称
}
对于获取Firefox 浏览器的名称和版本,可以如下:
else if (/rv:([^\)]+)\) Gecko\/\d{8}/.test(ua)) { engine.ver = RegExp['$1']; engine.gecko = true; if (/Firefox\/(\S+)/.test(ua)) { browser.ver = RegExp['$1']; //设置版本 browser.firefox = true; //填充保证为true browser.name = 'Firefox'; //设置名称 } }
对于获取Chrome 和safari 浏览器的名称和版本,可以如下:
else if (/AppleWebKit\/(\S+)/.test(ua)) { engine.ver = RegExp['$1']; engine.webkit = parseFloat(engine.ver); if (/Chrome\/(\S+)/.test(ua)) { browser.ver = RegExp['$1']; browser.chrome = true; browser.name = 'Chrome'; } else if (/Version\/(\S+)/.test(ua)) { browser.ver = RegExp['$1']; browser.chrome = true; browser.name = 'Safari'; } }
PS:对于Safari3 之前的低版本,需要做WebKit 的版本号近似映射。而这里,我们将不去深究,已提供代码。浏览器的名称和版本号,我们已经准确的获取到,最后,我们想要去获取浏览器所宿主的操作系统。
var system = { //操作系统 win : false, //windows mac : false, //Mac x11 : false //Unix、Linux }; var p = navigator.platform; //获取系统 system.win = p.indexOf('Win') == 0; //判断是否是windows system.mac = p.indexOf('Mac') == 0; //判断是否是mac system.x11 = (p == 'X11') || (p.indexOf('Linux') == 0) //判断是否是Unix、Linux
PS:这里我们也可以通过用户代理字符串获取到windows 相关的版本,这里我们就不去深究了,提供代码和对应列表。