本章内容
- 使用能力检测
- 用户代理检测的历史
- 选择检测方式
1. 能力检测
最广泛的客户端检测模式,又称特性检测。能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力。这种方式只需要确定浏览器支持特定的能力,就可以给出解决方案。如下:
if(object.properyInQuestion){
//使用object.properyInQuestion
}
//举例说明,早期IE5不支持document.getElementById()
//类似下面的能力检测代码
function getId(id){
if(document.getElementById(id)){
return document.getElementById(id)
}else if(document.all){
return document.all(id)
}else{
throw new Error('都不支持')
}
}
//理解能力检测,首先理解两个重要概念.
//第一就是先检测达成目的的最常用的特性.先检测最常用的特性可以保证代码最优化.
//第二就是必须测试实际要用到的特性.一个特性存在,不一定意味着另一个特性也存在.如下:
function getWidth(){
if(document.all){
//假设是IE
return document.documentElement.clientWidth //错误的用法
}else{
return window.innerWidth
}
}
1.1 更可靠的能力检测
//更可靠的能力检测
function isSort(object){
return !!object.sort
}
//检测某个属性是否存在并不能确定对象是否支持排序.更好的方式是检测sort是不是一个函数
function isSorttable(object){
return typeof object.sort == 'function'
}
//在可能的情况下,要尽量使用typeof进行能力检测.
//在IE8以及之前版本中不行
function hasElement(){
return typeof document.createElement == 'function'
}
//IE9修复了
//在IE中会导致错误
var xhr = new ActiveXObject('Microsoft.XMLHttp')
if(xhr.open){ //这里会发生错误
//执行操作
}
//在浏览器环境下测试任何对象的某个特性是否存在,如下:
function isHostMethod(obj,pro){
var t = typeof obj[pro]
return t == 'function' || (!!(t == 'object' && obj[pro])) || t == 'unknow'
}
1.2 能力检测,不是浏览器检测
var isFirefox = !!(navigator.vendor && navigator.vendorSub)
//
var isIe = !!(document.all && document.uniqueID)
//检测浏览器是否支持Netscape风格的插件
var hs = !!(navigator.plugins && navigator.plugins.length);
//确定浏览器是否具有DOM1级规定的能力
var hsdom1 = !!(document.getElementById && document.createElement && document.getElementsByTagName)
2.怪癖检测
//也就是检测浏览器中存在什么缺陷bug
var hasBug = function(){
var o = {toString:function(){}},
for(var prop in o){
if(prop == 'toString'){
return false
}
}
return true
}();
//另一个
var hasBug1 = function(){
var o = {toString:function(){}},
var count = 0;
for(var prop in o){
if(prop == 'toString'){
count++
}
}
return (count > 1)
}()
3. 用户代理检测
用户代理检测通过检测用户代理字符串来确定实际使用的浏览器。在每一次HTTP请求过程中,用户代理字符串作为相应首部发送的,而且该字符串可以通过JS的navigator.userAgent属性访问。
电子欺骗就是指浏览器通过在自己的用户代理字符串加入一些错误或误导性信息,来达到欺骗服务器的目的。
3.2 用户代理字符串检测技术
//该方式不推荐
if(isIE6 || isIE7){ //不推荐
//代码
}
//可以优化成下面的
if(ieVer >= 6){
//代码
}
//封装的检测脚本.基本代码结构如下:
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
};
//识别平台
var system = {
win:false,
mac:false,
x11:false
}
//在此检测呈现引擎.平台和设备
return {
engine : engine,
browser:browser,
system:system
}
}()
//可以配套使用下面的检测代码
if(client.engine.ie){ //如果是ie,client.id的值应该大于0
//针对IE的代码
}else if{client.engine.gecko > 1.5}{
if(clinet.engine.ver == '1.8.1'){
//针对这个版本执行某些操作
}
}
//将版本的字符串保存在了engine.ver中,浮点数值的版本保存在了engine.opera中
//检测opera
if(window.opera){
}
//检测webkit
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{
//近似的确定版本号
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)){
browserver = 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)
}
//有了上面的代码,可以在配套使用下面的直接使用逻辑
if(client.engine.webkit){
if(client.browser.chrome){
//执行针对chrome的代码
}else if(client.browser.safari){
//执行针对safari的代码
}
}else if(client.engine.gecko){
if(client.browser.firefox){
//执行针对firefox的代码
}else{
//执行针对其他gecko的代码
}
}
//检测平台
var p = navigator.platform
system.win = p.indexOf("Win") == 0
system.mac = p.indexOf("Mac") == 0;
system.x11 = (p.indexOf("X11") == 0) || (p.indexOf("Linux") == 0)
4. 小结
由于浏览器间存在差别,所以需要根据不同的浏览器能力编写不同的代码。下列常用的方法:
能力检测:编写代码之前检测特定浏览器的能力。例如,脚本在调用某个函数之前,可能要先检测该函数是否存在,能力检测无法精确的检测特定的浏览器和版本 。
怪癖检测:怪癖实际上是浏览器实现中存在的bug。怪癖检测无法精确的检测特定的浏览器和版本。
用户代理检测:通过检测用户代理字符串来识别浏览器。用户代理字符串中包含大量与浏览器有关的信息,包括浏览器、平台、操作系统以及浏览器版本。通过用户代理字符串可以检测出浏览器所用的呈现引擎以及所在的平台,包括移动设备和游戏系统。
在决定使用哪种客户端检测方式时,一般应优先考虑使用能力检测。怪癖检测是确定应该如何处理代码的第二选择。而用户代理检测是客户端检测的最后一种方案,因此这种方法对用户代理字符串具有很强的依赖性。