《JS高程(3)》客户端检测-第9章笔记(10)

来源:互联网 发布:小米note查看网络制式 编辑:程序博客网 时间:2024/06/07 18:07
  1. 使用能力检测
  2. 用户代理监测的历史
  3. 选择检测方式

    因各个浏览器之间不一致性,不得不采用各种客户端检测方法

能力检测

检测目的:识别浏览器的能力。

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

  • 先检测达成目的的最常用的性能,保证代码的优化;

  • 必须测试实际用到的特性。

更靠谱的能力检测

通过typeof确定是否为函数,进行能力检测。

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

typeof 操作符用于确定sort的却是函数,因此可以调用他对数据进行排序。
在可能的情况下,尽量使用typeof进行能力检测。特别是宿主对象没有义务让typeof返回合理值。

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

检测一个或几个特性并不能确定浏览器;
根据浏览器的不同将能力组合起来,一次性检测所有相关的特性,而不是分次检测。

//确定浏览器是否支持Netspace风格的插件var hasNSPlugins = !!(navigator.plugins && navigator.pligins.length);//确定浏览器是否具有DOM1级别规定的能力var hasDOM1 = !!(document.getElementById && document.createElement && document.getElementByTagName);

在得到布尔值后继续使用,从而节省重新检测能力的时间。

怪癖检测

目标:识别浏览器的特殊行为,知道浏览器存在什么缺陷.
“怪癖”即为bug。

var hasDontEnumQuik = function(){    var o = {toString : function(){}};    for(var props in o){        if (props == "toString"){             return false ;          }    }    return true;}();

通过一个匿名函数来测试该’怪癖’,函数中创建了衣蛾带有toString()方法的对象。在正确的ECMAScript实现中,toString应该在for-in循环中作为属性返回。
‘怪癖’的检测应在脚本开始时,尽早解决问题。

  1. IE8及更早版本中存在一个bug,即如果某个实例属性与[[Enumerable]]标记为false的某个原型属性同名,那么该实例属性将不会出现在for—in循环当中;

  2. Safari 3以前版本会枚举被隐藏的属性;

  3. cloneNode()方法不会复制添加到DOM节点中的javascript属性,例如事件处理程序等,IE在此存在一个bug,即它会复制事件处理程序;

  4. IE8及更早版本与其他浏览器处理空白字符的方式不一样,IE9之前的版本不会为空白符创建节点;

  5. IE8及较低版本不区分ID的大小写,如果页面中多个元素的的ID值相同,getElementById()只返回文档中第一次出现的元素;

  6. IE7及以下版本有一个有意思的怪癖:name特性与给定ID匹配的表单元素(<input>,<textarea>,<button>及<select>)也会被该方法返回

  7. IE7以前,通过getAttribute()方法访问style特性(返回一个对象)或者onclick这样的事件处理 特性时(返回一个函数),返回的值与属性的值相同,同时setAttribute()存在一些异常行为。通过这个方法设置的class和style特性,没有任何效果,设置事件处理程序特性是也一样。

用户代理检测

争议最大的客户端检测技术。

通过检测用户代理字符串确定实际使用的浏览器。

编写脚本的五大呈现引擎:IE , Gecko , Webkit , KHTML , Opera.

IE: IE Firefox: Gecko Safari : Webkit (Webkit原来是KHTML呈现引擎原来的一个分支,后来独立出来开源,专注呈现引擎开发) Chrome: Webkit linux: KHTML konqueror Opera: Opera(Presto)
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"){        //针对这个版本执行某些操作    }}

要正确的确认识别引擎,关键是检查顺序要正确。
第一步:识别Opera;

必须检测 window.opera对象

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

第二步:识别webkit;

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

第三步:识别khtml;

KHTML中也包含Gecko,在排除KHTML之前无法准确检测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);}

第四步:识别gecko ;

在排除webkit和khtml后就能确认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;

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);}
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 = parseInt(browser.ver);    }else if(/Version\/(\S+)/.test(ua)){        browser.ver = RegExp["$1"];        browser.safari = parseInt(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);}

useragentstring.com列出了各种浏览器的版本以及用户代理字符串。

0 0