你当前使用的浏览器的用户代理字符串是:
识别呈现引擎
确切知道浏览器的名字和版本号不如确切知道它使用的是什么呈现引擎。如果Firefox、Camino和Netscape都使用相同版本的Gecko,那它们一定支持相同的特性。类似地,不管是什么浏览器,只要它跟Safari 3使用的是同一个版本的WebKit,那么该浏览器也就跟Safari 3具备同样的功能。因此,我们要编写的脚本将主要检测五大呈现引擎:IE、Geoko、WebKit、KHTML和Opera。
要正确地识别呈现引擎,关键是检测顺序要正确。由于用户代理字符串存在诸多不一致的地方,如果检测顺序不对,很可能会导致检测结果不正确。为此,第一步就是识别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.opear = 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中。
接下来要测试的呈现引擎是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中,将浮点数值形式的版本保存在engine.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) || /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); }
Gecko的版本号位于字符串rv:与一个闭括号之间,因此为了提取出这个版本号,正则表达式要查找所有不是闭括号的字符,还要查找字符串Gecko/后跟8个数字。如果上述模式匹配,就提取出版本号并将其保存在相应的属性中。最后一个要检测的呈现引擎就是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) || /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); }
以上呈现引擎检测脚本的最后一部分,就是在正则表达式中使用取反的字符类来取得不是分号的所有字符。IE通常会保证以标准浮点数值形式给出其版本号,但有时候也不一定。因此,取所的字符类[^;]可以确保取得多个小数点以及任何可能的字符。