码迷,mamicode.com
首页 > 其他好文 > 详细

客户端检测

时间:2016-04-13 19:00:01      阅读:249      评论:0      收藏:0      [点我收藏+]

标签:

检测Web客户端的手段很多,而且各有利弊。不到万不得已,就不要使用客户端检测。先设计最通用的方案,然后再使用特定于浏览器的技术增强该方案。

一、能力检测

  能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力。能力检测的基本模式如下:

if (object.propertyInQuestion) {
    // 使用 object.propertyInQuestion
}

1.1 更可靠的能力检测

  能力检测是检测某个特性是否会按照适当方式行事,而不是仅仅某个特性是否存在。

// 不要这样做!这不是能力检测-只检测了是否存在相应的属性
function isSortable(object) {
    return !!object.sort;
}

更好的方式是检测sort是不是一个函数

// 这样更好:检查是不是函数
function isSortable(object) {
    return typeof object.sort == "function";
}

注意:宿主对象(DOM对象是一种)没有义务让typeof返回合理的值,特别是在IE8-中,宿主对象是通过COM而非JScript实现的。对函数使用typeof运算符会返回“object”,而不是期待的“function”。还有其它的一些对象有怪异的行为。在浏览器换下可以使用如下函数测试任何对象的某个特性是否存在。

// 作者:Peter Michaux
function isHostMethod(object, property) {
    var t = typeof object[property];
    return t == ‘function‘ ||
                (!!(t == ‘object‘ && object[property])) || t == ‘unknown‘;
}

1.2 能力检测,不是浏览器检测

  根据浏览器不同将能力组合起来时更可取的方式。如果你知道自己的应用程序需要使用某些特定的浏览器特性,那么最好是一次性检测所有相关特性,而不是分别检测。

// 确定浏览器是否支持Netscape风格的插件
var hasNSPlugins = !!(navigator.plugins && navigator.plugins.length);

// 确定浏览器是否具有DOM1级规定的能力
var hasDOM1 = !! (document.getElementById && document.createElement && document.getElementByTagName);

得到的布尔值可以在以后继续使用,从而节省重新检测能力的时间。实际开发中,应该将能力检测作为确定下一步解决方案的依据,而不是用来判断用户使用的是什么浏览器。

二、怪癖检测

怪癖检测的目标是识别浏览器的特殊行为。着通常需要运行一小段代码,以确定某一个特性不能正常工作。IE8-中的一个bug是,如果存在某个实例属性与[[Enumerable]]标记为false的某个原型属性同名,那么该实例属性将不会出现在for-in循环中。Safari3-中会枚举被隐藏的属性。

三、用户代理检测

  用户代理检测通过检测用户代理字符串来确定实际使用的浏览器。又有历史原型,这种检测是一种无法完美的检测。一般情况下,知道呈现引擎和最低限度的版本就足以决定正确的操作方法了。

3.1 识别呈现引擎

  主流的五大呈现引擎: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 }; }();

如果检测到了哪个呈现引擎,就以浮点数值形式写入相应属性,而呈现引擎的完整版本(一个字符串),则被写入ver属性。要正确识别呈现引擎,关键是检测顺序要正确,第一步是要识别Opera,代码如下:

if (window.opera) {
    engine.ver = window.opera.version();
    engine.opera = parseFloat(engine.ver);
}

第二步要识别WebKit,示例代码如下:

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);
}

第三步要识别KHTML,示例代码如下:

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);
}

第四部要识别Gecko,示例代码如下:

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);
}

最好一步识别IE,示例代码如下:

else if (/MSIE ([^;]+)/.test(ua)) {
    engine.ver = RegExp["$1"];
    engine.ie = parseFloat(engine.ver);
}

3.2 识别浏览器

  Safari浏览器和Chrome浏览器都使用WebKit作为呈现引擎,当它们的JavaScript引擎不一样。对于它们,有必要为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 }; }();

由于大多数浏览器与其呈现引擎密切相关,所有可以混合检测呈现引擎和浏览器。

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)) {
        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);
}

有了这些代码以后,我们就 可以编写下面的逻辑:

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浏览器的代码
    }
}

3.3 识别平台

  具有各种平台版本的浏览器在不同的平台下可能会有不同的问题。为此,还需要给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
    };
    
    var system = {
        win: false,
        mac: false,
        x11: false
    };
    // 此处识别呈现引擎和浏览器和平台

    return {
        engine: engine,
        browser: browser,
        system: system
    };
}();    

确定平台可以检测navigator.platform比检测用户代理字符串更简单。代码如下:

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);

3.4 识别Windows操作系统

3.5 识别移动设备

  要识别移动设备,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
    };
    
    var system = {
        win: false,
        mac: false,
        x11: false,
        iphone: false,
        ipod: false,
        ipad: false,
        ios: false,
        android: false,
        nokiaN: false,
        winMobile: false
    };
    // 此处识别呈现引擎和浏览器和平台

    return {
        engine: engine,
        browser: browser,
        system: system
    };
}();    

相应的检测代码是:

system.iphone = ua.indexOf("iPhone") > -1;
system.ipod = ua.indexOf("iPod") > -1;
system.ipad = ua.indexOf("iPad") > -1;

// 检测Android版本
if (/Android (\d+\.\d+)/.test(ua)) {
    system.android = parseFloat(RegExp.$1);
}

3.6 识别游戏系统

  

system.wii = ua.indexOf("Wii") > -1;
system.ps = /playstation/i.test(ua);

4 小结

  用户代理检测是客户端检测的最后一个选择,优先采用能力检测和怪癖检测。用户代理检测一般适用如下情形。

  1)不能直接准确地使用能力检测或怪癖检测,因为有些浏览器实现了存根函数。

  2)同一款浏览器在不同平台下具备不同的能力。

  3)为了跟踪分析等目的需要知道确切的浏览器。

  

 

客户端检测

标签:

原文地址:http://www.cnblogs.com/TwoWaterLee/p/5388173.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!