考虑到历史原因以及现代浏览器中用户代理字符串的使用方式,通过用户代理字符串来检测特定的浏览器并不是一件轻松的事。因此,首先要确定的往往是你需要多么具体的浏览器信息。一般情况下,知道呈现引擎和最低限度的版本就足以决定正确的操作方法了。例如,我们不推荐使用下列代码:
if (isIE6 || isIE7) { //不推荐!!!
//代码
}
这个例子是想要在浏览器为IE6或IE7时执行相应代码。这种代码其实是很脆弱的,因为它要依据特定的版本来决定做什么。如果是IE8怎么办呢?只要IE有新版本出来,就必须更新这些代码。不过,像下面这样使用相对版本号则可以避免此问题:
if (ieVer >=6){
//代码
}
这个例子首先检测IE的版本号是否至少等于6,如果是则执行相应操作。这样就可以确保相应的代码将来照样能够起作用。我们下面的浏览器检测脚本就将本着这种思路来编写。
- 识别呈现引擎
如前所述,确切知道浏览器的名字和版本号不如确切知道它使用的是什么呈现引擎。如果Firefox、Camino和Netscape都使用相同版本的Gecko,那它们一定支持相同的特性。类似地,不管是什么浏览器,只要它跟Safari 3使用的是同一个版本的WebKit,那么该浏览器也就跟Safari 3具备同样的功能。因此,我们要编写的脚本将主要检测五大呈现引擎:IE、Gecko、WebKit、KHTML和Opera。
为了不在全局作用域中添加多余的变量,我们将使用模块增强模式来封装检测脚本。检测脚本的基本代码结构如下所示:
var client = function(){
var engine = {
//呈现引擎
ie: 0,
gecko: 0,
webkit: 0,
khtml: 0,
opera: 0,
//具体的版本号
ver: null
};
//在此检测呈现引擎、平台和设备
return {
engine : engine
};
}();
这里声明了一个名为client的全局变量,用于保存相关信息。匿名函数内部定义了一个局部变量engine,它是一个包含默认设置的对象字面量。在这个对象字面量中,每个呈现引擎都对应着一个属性,属性的值默认为0。如果检测到了哪个呈现引擎,那么就以浮点数值形式将该引擎的版本号写入相应的属性。而呈现引擎的完整版本(是一个字符串),则被写入ver属性。作这样的区分可以支持像下面这样编写代码:
if (client.engine.ie) { //如果是IE,client.ie的值应该大于0
//针对IE的代码
} else if (client.engine.gecko > 1.5){
if (client.engine.ver == "1.8.1"){
//针对这个版本执行某些操作
}
}
在检测到一个呈现引擎之后,其client.engine中对应的属性将被设置为一个大于0的值,该值可以转换成布尔值true。这样,就可以在if语句中检测相应的属性,以确定当前使用的呈现引擎,连具体的版本号都不必考虑。鉴于每个属性都包含一个浮点数值,因此有可能丢失某些版本信息。例如,将字符串"1.8.1"传入parseFloat()后会得到数值1.8。不过,在必要的时候可以检测ver属性,该属性中会保存完整的版本信息。
要正确地识别呈现引擎,关键是检测顺序要正确。由于用户代理字符串存在诸多不一致的地方,如果检测顺序不对,很可能会导致检测结果不正确。为此,第一步就是识别Opera,因为它的用户代理字符串有可能完全模仿其他浏览器。我们不相信Opera,是因为(任何情况下)其用户代理字符串(都)不会将自己标识为Opera。
要识别Opera,必须得检测window.opera对象。Opera 5及更高版本中都有这个对象,用以保存与浏览器相关的标识信息以及与浏览器直接交互。在Opera 7.6及更高版本中,调用version()方法可以返回一个表示浏览器版本的字符串,而这也是确定Opera版本号的最佳方式。要检测更早版本的Opera,可以直接检查用户代理字符串,因为那些版本还不支持隐瞒身份。不过,2007底Opera的最高版本已经是9.5了,所以不太可能有人还在使用7.6之前的版本。那么,检测呈现引擎代码的第一步,就是编写如下代码:
if (window.opera){
engine.ver = window.opera.version();
engine.opera = parseFloat(engine.ver);
}
这里,将版本的字符串表示保存在了engine.ver中,将浮点数值表示的版本保存在了engine.opera中。如果浏览器是Opera,测试window.opera就会返回true;否则,就要看看是其他的什么浏览器了。
应该放在第二位检测的呈现引擎是WebKit。因为WebKit的用户代理字符串中包含"Gecko"和"KHTML"这两个子字符串,所以如果首先检测它们,很可能会得出错误的结论。
不过,WebKit的用户代理字符串中的"AppleWebKit"是独一无二的,因此检测这个字符串最合适。下面就是检测该字符串的示例代码:
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);}
代码首先将用户代理字符串保存在变量ua中。然后通过正则表达式来测试其中是否包含字符串"AppleWebKit",并使用捕获组来取得版本号。由于实际的版本号中可能会包含数字、小数点和字母,所以捕获组中使用了表示非空格的特殊字符(\S)。用户代理字符串中的版本号与下一部分的分隔符是一个空格,因此这个模式可以保证捕获所有版本信息。test()方法基于用户代理字符串运行正则表达式。如果返回true,就将捕获的版本号保存在engine.ver中,而将版本号的浮点表示保存在engine.webkit中。WebKit版本与Safari版本的详细对应情况如下表所示。
Safari版本号最低限度的WebKit版本号Safari版本号最低限度的WebKit版本号1.0至1.0.285.71.3312.11.0.385.8.21.3.1312.51.1至1.1.11001.3.2312.81.2.2125.22.04121.2.3125.42.0.1412.71.2.4125.5.52.0.2416.112.0.3417.93.0.4523.102.0.4418.83.1525
有时候,Safari版本并不会与WebKit版本严格地一一对应,也可能会存在某些小版本上的差异。这个表中只是列出了最可能的WebKit版本,但不保证精确。
接下来要测试的呈现引擎是KHTML。同样,KHTML的用户代理字符串中也包含"Gecko",因此在排除KHTML之前,我们无法准确检测基于Gecko的浏览器。KHTML的版本号与WebKit的版本号在用户代理字符串中的格式差不多,因此可以使用类似的正则表达式。此外,由于Konqueror 3.1及更早版本中不包含KHTML的版本,故而就要使用Konqueror的版本来代替。下面就是相应的检测代码。
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);}
与前面一样,由于KHTML的版本号与后继的标记之间有一个空格,因此仍然要使用特殊的非空格字符来取得与版本有关的所有字符。然后,将字符串形式的版本信息保存在engine.ver中,将浮点数值形式的版本保存在engin.khtml中。如果KHTML不在用户代理字符串中,那么就要匹配Konqueror后跟一个斜杠,再后跟不包含分号的所有字符。
在排除了WebKit和KHTML之后,就可以准确地检测Gecko了。但是,在用户代理字符串中,Gecko的版本号不会出现在字符串"Gecko"的后面,而是会出现在字符串"rv:"的后面。这样,我们就必须使用一个比前面复杂一些的正则表达式,如下所示。
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)) {
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);}
Gecko的版本号位于字符串"rv:"与一个闭括号之间,因此为了提取出这个版本号,正则表达式要查找所有不是闭括号的字符,还要查找字符串"Gecko/"后跟8个数字。如果上述模式匹配,就提取出版本号并将其保存在相应的属性中。Gecko版本号与Firefox版本号的对应关系如下表所示。
Firefox版本号最低限度的Gecko版本号Firefox版本号最低限度的Gecko版本号1.01.7.53.51.9.11.51.8.03.61.9.22.01.8.14.02.0.03.01.9.0
与Safari跟WebKit一样,Firefox与Gecko的版本号也不一定严格对应。
最后一个要检测的呈现引擎就是IE了。IE的版本号位于字符串"MSIE"的后面、一个分号的前面,因此相应的正则表达式非常简单,如下所示:
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)) {
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);}
以上呈现引擎检测脚本的最后一部分,就是在正则表达式中使用取反的字符类来取得不是分号的所有字符。IE通常会保证以标准浮点数值形式给出其版本号,但有时候也不一定。因此,取反的字符类[^;]可以确保取得多个小数点以及任何可能的字符。
- 识别浏览器
大多数情况下,识别了浏览器的呈现引擎就足以为我们采取正确的操作提供依据了。可是,只有呈现引擎还不能说明存在所需的JavaScript功能。苹果公司的Safari浏览器和谷歌公司的Chrome浏览器都使用WebKit作为呈现引擎,但它们的JavaScript引擎却不一样。在这两款浏览器中,client.webkit都会返回非0值,但仅知道这一点恐怕还不够。对于它们,有必要像下面这样为client对象再添加一些新的属性。
var client = function(){
var engine = {
//呈现引擎
ie: 0,
gecko: 0,
webkit: 0,
khtml: 0,
opera: 0,
//具体的版本
ver: null
};
var browser = {//浏览器ie: 0,firefox: 0,safari: 0,konq: 0,opera: 0,chrome: 0,//具体的版本ver: null};
//在此检测呈现引擎、平台和设备
return {
engine: engine,
browser: browser
};
}();
代码中又添加了私有变量browser,用于保存每个主要浏览器的属性。与engine变量一样,除了当前使用的浏览器,其他属性的值将保持为0;如果是当前使用的浏览器,则这个属性中保存的是浮点数值形式的版本号。同样,ver属性中在必要时将会包含字符串形式的浏览器完整版本号。由于大多数浏览器与其呈现引擎密切相关,所以下面示例中检测浏览器的代码与检测呈现引擎的代码是混合在一起的。
//检测呈现引擎及浏览器
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还是Safariif (/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 {//近似地确定版本号var safariVersion = 1;if (engine.webkit safariVersion = 1;} else if (engine.webkit safariVersion = 1.2;} else if (engine.webkit 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);
//确定是不是Firefoxif (/Firefox/(\S+)/.test(ua)){browser.ver = RegExp["1"];browser.firefox = parseFloat(browser.ver);}
} else if (/MSIE ([^;]+)/.test(ua)){
engine.ver = browser.ver = RegExp["1"];engine.ie = browser.ie = parseFloat(engine.ver);
}
对Opera和IE而言,browser对象中的值等于engine对象中的值。对Konqueror而言,browser.konq和browser.ver属性分别等于engine.khtml和engine.ver属性。
为了检测Chrome和Safari,我们在检测引擎的代码中添加了if语句。提取Chrome的版本号时,需要查找字符串"Chrome/"并取得该字符串后面的数值。而提取Safari的版本号时,则需要查找字符串"Version/"并取得其后的数值。由于这种方式仅适用于Safari 3及更高版本,因此需要一些备用的代码,将WebKit的版本号近似地映射为Safari的版本号(参见上一小节中的表格)。
在检测Firefox的版本时,首先要找到字符串"Firefox/",然后提取出该字符串后面的数值(即版本号)。当然,只有呈现引擎被判别为Gecko时才会这样做。
有了上面这些代码之后,我们就可以编写下面的逻辑。
if (client.engine.webkit) { //if it’s WebKit
if (client.browser.chrome){
//执行针对Chrome的代码
} else if (client.browser.safari){
//执行针对Safari的代码
}
} else if (client.engine.gecko){
if (client.browser.firefox){
//执行针对Firefox的代码
} else {
//执行针对其他Gecko浏览器的代码
}
}
想要了解更多Java基础知识,可以点击评论区链接和小编一起学习java吧,此视频教程为初学者而著,零基础入门篇!给同学们带来全新的Java300集课程啦!java零基础小白自学Java必备优质教程_手把手图解学习Java,让学习成为一种享受_哔哩哔哩_bilibili