Javascript高级程序设计——客户端检测

     ECMAScript虽然是Javascript的核心,但是要在web中使用Javascript,那么BOM才是核心,BOM为我们提供了操作访问浏览器对象的借口,

但是由于BOM没有标准规范,导致存在不一致的问题,所以这里需要客户端检测的方法,突破局限。

  先找出设计通用的的方案,然后再使用特定与浏览器的技术增强该方案。

一、能力检测

  能力检测的目的不是识别浏览器,而是识别浏览器的能力。不必顾及特定的浏览器,只需确定浏览器支持特定的能力。

//浏览器检测的基本模式
if(object.property){
    使用object.property
}

  先检测常用的特性,保证了代码最优化。

//上个例子中的代码利用类型转换来确定某个对象是否存在,但这不能保证该成员是不是想要的。
这里更可靠的能力检测
function betterCheck(property){
    return (typeof object.property == "function");
}

 二、怪癖检测

  怪癖检测的目标是识别浏览器的特殊行为。只是检测浏览器的存在缺陷。

//例如
早期IE8中,如果实例属性与[[enumerable]]为false的某个原型同名,那么这个属性遍不会被for-in循环枚举。可以通过下面的代码来检测这个”怪癖“

var hasEnumQuirk = function () {
    
    var o = { toString : function () {} };
    for (var pro in o ){
    if(pro == "toString")
        return false;
    }

    return true;
}

 怪癖一般都是浏览器所独有的,通常被归为bug,一般仅检测有直接影响的“怪癖”。

三、用户代理检测

  在浏览器每次发送的http时,都会将userAgent用户代理字符串作为响应首部发送,可以通过navigator.userAgent访问。

  由于经过浏览器大战,现在的浏览器的用户代理都是通过电子欺骗来指定一些误导信息,欺骗服务器。

1、识别呈现引擎

//为了减少全局变量,这里使用增强模块模式。在内部声明了浏览器的呈现引擎,浏览器版本和平台信息
var client = (function () {
 
    //呈现引擎
    var engine = {
         
        ie : 0,
        gecko : 0,
        webkit : 0,
        khtml : 0,
        opera : 0,
 
        ver : null
    };
 
    //浏览器版本
    var broswer = {
         
        ie : 0,
        firefox : 0,
        chrome : 0,
        safari : 0,
        konq : 0,
        opera : 0,
 
        ver : null
    };
 
    //平台信息
    var system = {
         
        win : false,
        mac : false,
        x11 : false,
 
        //移动设备
        iphone : false,
        ipod : false,
        ipad : false,
        ios : false,
        andriod : false,
        nokia : false,
        winMobile : false,
 
        //游戏平台
 
        will : false,
        ps : false
    };
 
 
    //用户代理检测
    var ua = navigator.userAgent;
    //opera会将自己完全伪造成其他浏览器所以先检测它
    if (window.opera){
        engine.opera = broswer.opera = parseInt(engine.ver);
        engine.ver = broswer.ver = window.opera.version();
    }else if (/AppleWebKit/(S+)/.test(ua)){
    //webkit引擎的独有特征是AppleWebKit,利用正则表达式来获取版本号
        engine.ver = RegExp.$1;
        engine.webkit = parseInt(engine.ver);
 
        //确认引擎后可以判断浏览器版本,chrome or safari
        if (/chrome/(S+)/.test(ua)){
            broswer.ver = RegExp.$1;
            broswer.chrome = parseFloat(broswer.ver);
        }else if (/Version/(S+)/.test(ua)){
            broswer.ver = RegExp.$1;
            broswer.safari = parseFloat(broswer.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;
            }
 
            broswer.ver = broswer.safari = safariVersion;
        }
    } else if (/KHTML/(S+)/.test(ua) || /Konqueror/[^;]+/.test(ua)){
        engine.ver = broswer.ver = RegExp.$1;
        engine.konq = broswer.konq = parseFloat(engine.ver);
    } else if (/rv:([^)]+)) Gecko/d{8}/.test(ua)){
        engine.ver = RegExp.$1;
        engine.gecko = parseInt(engine.ver);
 
        //是否是firefox浏览器
        if (/firefox/(S+)/i.test(ua)){
            broswer.ver = RegExp.$1;
            broswer.firefox = parseFloat(broswer.ver);
        }
        //如果这里没有检测到的firefox岂不是没有浏览器的版本信息了?
    } else if (/MSIE ([^;]+)/.test(ua)){
        engine.ver = broswer.ver = RegExp.$1;
        engine.ie = broswer.ie = parseFloat(engine.ver);
    }
 
    //检测浏览器,不已经检测过了吗?
    broswer.ie = engine.ie;
    broswer.opera = engine.opera;
 
    //检测平台的开始自动判断平台
    var p = navigator.platform;
    system.win = p.indexOf("Win") == 0;
    system.mac = p.indexOf("Mac") == 0;
    system.xll = (p == "X11" || p.indexOf("Linux") == 0);
 
    if (system.win){
        if (/Win(?:dows )?([^do]{2})s?(d+.d+)?/.test(ua)){
            if (RegExp.$1 == "NT"){
                switch(RegExp.$2){
                    case "5.0":
                        system.win = "2000";
                        break;
 
                    case "5.1":
                        system.win = "xp";
                        break;
 
                    case "6.0":
                        system.win = "Visita";
                        break;
 
                    case "6.1":
                        system.win = "7";
                        break;
 
                    default :
                        system.win = "NT";
                        break;
                }
            } else if (RegExp.$1 == "9x"){
                system.win = "ME";
            } else {
                system.win = RegExp.$1;
            } 
        }
    }
 
    system.iphone = ua.indexOf("iPhone") > -1; 
    system.ipod = ua.indexOf("ipod") > -1; 
    system.ipod = ua.indexOf("ipad") > -1; 
    system.nokia = ua.indexOf("NokiaN") > -1;
 
    //windowMobile
    if (system.win == "CE"){
        system.winMobilem = system.win;
    } else if (system.win == "Ph"){
        if(/Windows Phone OS (d+.d+)/.test(ua)){
            system.win = "Phone";
            system.winMobilem = parseFloat(RegExp.$1);
        }
    }
 
    //ios
    if (system.mac $$ ua.indexOf("Mobile") > -1){
        if (/CPU (?:iPhone ) ?OS (d+.d+)/.test(ua)){
            system.iso = parseFloat(RegExp.$1.replace("_", "."));
        } else {
            system.iso = 2;
        })
    }
 
    //检测安卓
    if (/Andriod (d+ . d+)/.test(ua)){
        system.andriod = parseFloat(RegExp.$1);
    }
 
    system.will = ua.indexOf("Wii") > -1;
    system.ps = /PLAYSTATION/i.test(ua);
 
    return {
        engine : engine,
        broswer : broswer,
        system : system
    };
 
})();

 浏览器检测只是最后一中选择,只要有可能就应该优先采用能力检测和怪癖检测。适用以下三种情形:

1、不能直接准确的使用能力检测和怪癖检测

2、浏览器在不同平台下不同的能力,需要检测平台。

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

小结:

客户端检测时有争议的,由于浏览器之间存在差别,通常需要根据不同浏览器,写不同的代码。客户端检测的常用方法:

  1. 能力检测,在编写代码前,先检测浏览器的能力,把注意集中在浏览器的能力存在上。
  2. 怪癖检测,浏览器中的bug的检测
  3. 用户代理检测,根据用户代理字符串来识别浏览器。

一般,优先考虑能力检测,怪癖检测时第二选择,引文用户代理检测对用户代理字符串的依赖非常强大

原文地址:https://www.cnblogs.com/yangxunwu1992/p/4785474.html