javascript框架设计之浏览器的嗅探和特征侦测


Posted in Javascript onJune 23, 2015

浏览器的嗅探现在已经不推荐了,但在某些场合还是需要的。比如一些统计脚本。在标准浏览器里,提供了document.implementation.hasfeature,可惜有bug,不准确,目前,w3c又推出了CSS.supports方法,显示出大家对这块的关注。

1.判定浏览器。

主流的浏览器有ie firefox opera chorme safari 早期这些框架都是通过navigator.userAgent进行判定,目前国外的浏览器几乎都是可以判定的。

关于浏览器的判断脚本,jQuery已经移出本体,形成一个插件。更多的方式不多介绍,

移动设备的相关判定,这个建议看jQuery mobile与zepto的源代码。

    isIPone = /isIPone/i.test(navigator.userAgent);

    isIPone4 = window.devicePixelRatio >= 2 //在网页中,pixel与point比值称为device-pixel-ratio,普通设备都是1,iPhone4是2,有些 安卓机型是1.5

    isIpad = /ipad/i.test(navigator.userAgent)

    isAndroid = /android/i.test(navigator.userAgent)

    isIOS = isIPone || isIpad

国内的浏览器判定可以看Tangrame或qwrap,它们基本是IE,webkit,blink内核。

2.事件的支持侦测

prototype的核心成员kangax写了一篇文章,来判断浏览器对某种事件的支持。里面给出的实现如下:

var isEventSupported = (function() {
    var TAGNAMES = {
      'select':'input','change':'input',
      'submit':'form','reset':'form',
      'error':'img','load':'img','abort':'img'
    }
    function isEventSupported(eventName){
      var el = document.createElement(TAGNAMES[eventName] || 'div');
      eventName = 'on' + eventName;
      var isSupported = (eventName in el);
      if (!isSupported) {
        el.setAttribute(eventName, 'return;');
        isSupported = typeof el[eventName] == 'function';
      }
      el = null;
      return isSupported;
    }
    return isEventSupported;
  })();

现在jQuery等框架都是使用脚本的简化版

不过哪一个也好,这种检测只对DOM0奏效,像DOMMouseScroll DOMContentLoaded DOMFocusIn DOMFocusOut DOMSubtreeModified DOMNodeInserted DOMNodeRemoved DOMNodeRemovedFromDocument DOMNodeInsertedIntoDocument DOMAttrModified DOMCharactorDataModified这些以DOM开头的就无能为力了。

这些事件中,有的非常有用,如DOMMouseScroll,firefox一直不支持mousesheel,只能用它做替代品。
DOMContentLoaded是实现domReady的重要事件;DOMNodeRemoved是判定元素是否从其父节点移除,父节点可能是其它元素节点或文档碎片;DOMNodeRemovedFromDocument 是移离DOM树,DOMAttrModified 以前经常用于模拟IE的onpropertyChange

css3添加两种动画,一种是transition动画,另外一种是keyframe补间动画。它们在事件结束时都用事件回调。但在标准化过程中,浏览器给它们起的名字相当于没规则。这个也需要预先侦测出来。

下面是bootstrap的实现。听说来源于modernizr,比较粗糙。比如你使用的Oprera已经支持不带事件标准事件名。它还是返回oTransitionEnd.

$.supports.transition = (function(){
    var transitionEnd = (function(){
      var el = document.createElement('bootstarp'),
          transEndEventNames = {
            'WebkitTransition':'webkitTransitionEnd',
            'MozTransition':'transitionend',
            'OTransition':'OTransitionEnd otransitionend',
            'transition':'transitionend'
          };
        for (var name in transEndEventNames){
          if (el.style[name] !== undefined){
            return transEndEventNames[name]
          }
        }
    }());
    return transitionEnd && {
      end: transitionEnd
    }
  })();

keyframe补间动画来自mass的fx_neo模块

var eventName = {
    AnimationEvent:'animationend',
    WebKirAnimationEvent: 'WebKirAnimationEnd'
  },animationend;
  for(var name in eventName) {
    if (/object|function/.test(typeof window[name])){
      animationend = eventName[name]
      break
    }
  }

3.样式的支持侦探

css3带来许多好用的样式,但是麻烦的是每个浏览器都有自己的私有前缀,massFramework提供了一个cssName方法来处理它们,有就返回可用的驼峰样式名,没有就null

var prefixes = ['','-webkit-','-o-','-moz-','-ms-'];
  var cssMap = {
    "float" : $.support.cssFloat ? 'cssFloat' : 'styleFloat',background:'backgroundColor'
  };
  function cssName(name, host, camelCase){
    if(cssMap[name]) {
      return cssMap[name];
    }
    host = host || document.documentElement
    for (var i = 0 || n = prefixes.length; i < n; i++) {
      camelCase = $.String.camelize(prefixes[i] + name);
      if (camelCase in host) {
        return (cssMap[name] = camelCase)
      }
    }
    return null
  }

一个样式对于N种样式值,比如display有n种取值,如果要侦测浏览器是否支持某一种,会很麻烦。为此,浏览器做了一个善举,给出一个css.supports的API,如果不支持,则尝试下一个开源项目。显然,不是很完美。

https://github.com/termi/CSS.supports

4.jQuery的一些常用的特征的含义

jQuery在support模块例举了一些常用的DOM特征支持情况,不过名字起的很怪,不同版本差别也很大,本章以jQuery1.8为准。

leadingWhitespace:判定浏览器在进行innerHTML赋值时,是否存在trimLeft操作,这个功能原本是IE发明的,结果其他浏览器认为要忠于以后的原始值,最前面的空白不能神略掉,要变成一个文本节点,最终IE678返回false,其他浏览器返回true

tobody:指在用innerHTML动态创建元素时,浏览器是否会在table内自动补上tobody,jQuery希望浏览器别处理,让jQuery来补全。判断浏览器是否只能插入tobody。在表格布局的年代,这个特性十分受用。如果没有tbody,table会在浏览器解析到闭合标签时才显示出来。如果起始标签和闭合标签相隔很远,换言之,这个表格很长,用户会什么都看不到,但有了tbody分段显示和识别,避免了长时间空白后一下子显示出来的情况。

    var div = document.createElement("div");

    div.innerHTML = '<table></table>'

    alert(div.innerHTML) //=>ie678返回<table><tbody></tbody></table>,其它返回<table></table>

html.Serialize:判断浏览器是否完好支持用innerHTML转换一个符合html标签规则的字符串为一个元素节点,此过程jQuery称为序列化,但IE支持不够完好。包括scirpt link style mata在内的no-scope元素都转换失败。

style:这个命名很难看懂,不看代码不知道什么意思,真像是判定getAttribute是否返回style的用户预设值。IE678没有返回区分特性的特征,返回一个CSSStyleDeclaration对象。

hrefNormalized:判定getAttribute能否返回href的用户预设值。IE会补充给你完整的路径给你

opacity:判定浏览器是否支持opacity属性,ie678要使用滤镜

cssFloat: 判定float的样式在DOM的名字是那个,W3c为cssFloat,IE678为styleFloat

CheckOn: 在大多数浏览器中checkBox的value为on,chorme返回空字符串

optSelected: 判定是否正确取得动态添加option元素的seleted,ie6-10与老版的safari对动态添加option没有设置为true。解决办法,在访问selected属性前,先访问父节点的selectedIndex属性,再强制计算option的seleted.

<select id='optSelected'></select>
<script type="text/javascript">
  var select = document.getElementById('optSelected');
  var option = document.createElement('option');
  select.appendChild(option);
  alert(option.selected);
  select.selectedIndex;
  alert(option.selected)
</script>

optDisabled : 判定select元素的disable属性是否影响到子元素的disabled取值.在safari中,一旦select元素被disabled,它的子元素也disabled,导致一个值也取不到

checkClone:是指一个checkbox元素,如果设置了checked=true,且在多次克隆后,它的复制品能否保持为true。这个方法只有在safari4中返回false,其它的都true

inlineBlockNeedsLayout:判定是否使用hasLayout方法让dispaly:inline-block生效。这个方法只有ie678为true

getSetAttribute:判定是否区分特性属性,只有ie678为false

noCloneEvent:判定在克隆元素时是否克隆attachEvent绑定事件。只有旧版本的ie及其兼容模式返回false

enctype:判定浏览器是否支持encoding属性,ie67使用encoding属性来代替

boxModel:判定浏览器是否在content-box盒子渲染模式下

submitBubbles, changeBubbles, focusinBubble:判定浏览器是否支持这些事件,一直冒泡到document

shrinkWrapBlocks:判定元素是否会被子元素撑开。在IE678中,非替换元素在设置了大小与hasLayout的情况下,将将其父级元素撑大。

html5Clone:判定能否使用cloneNode克隆HTML5新标签 ,旧版本的IE不支持。需要用到outerHTML

deleteExpando:判定能否删除元素节点上的自定义元素,这用于jQuery缓存系统。旧版本的IE不支持,直接undefined

pixelPosition:判定getComputedStyle能否转换元素的top left bottom right元素的百分比值。这个在webkit系统会出现问题,需要用到 Dean Edwards神的hack

reliableMarginRight:判定getComputedStyle能否正确的取得元素的marginRiht.

clearCloneStyle :ie9 10 会出现奇怪的bug,当复制了一个元素的background-*样式的元素,对复制的元素进行清空时,会清空原来的样式。

随着浏览器疯狂更新版本,标准浏览器引发的各种bug已经超越IE,特征侦测不退反进,越来越重要了。

以上所述就是本文的全部内容了,希望大家能够喜欢。

Javascript 相关文章推荐
JavaScript中:表达式和语句的区别[译]
Sep 17 Javascript
jquery实现图片灯箱明暗的遮罩效果
Nov 15 Javascript
基于jquery自定义的漂亮单选按钮RadioButton
Nov 19 Javascript
JavaScript中检查对象property的存在性方法介绍
Dec 30 Javascript
bootstrap multiselect下拉列表功能
Aug 22 Javascript
javascript自定义事件功能与用法实例分析
Nov 08 Javascript
vue中前进刷新、后退缓存用户浏览数据和浏览位置的实例讲解
Sep 21 Javascript
了解在JavaScript中将值转换为字符串的5种方法
Jun 06 Javascript
Smartour 让网页导览变得更简单(推荐)
Jul 19 Javascript
深入理解webpack process.env.NODE_ENV配置
Feb 23 Javascript
three.js 制作动态二维码的示例代码
Jul 31 Javascript
微信小程序连续签到7天积分获得功能的示例代码
Aug 20 Javascript
简述AngularJS相关的一些编程思想
Jun 23 #Javascript
javascript框架设计之种子模块
Jun 23 #Javascript
在JavaScript的AngularJS库中进行单元测试的方法
Jun 23 #Javascript
javascript框架设计之框架分类及主要功能
Jun 23 #Javascript
js的flv视频播放器插件使用方法
Jun 23 #Javascript
使用Raygun来自动追踪AngularJS中的异常
Jun 23 #Javascript
使用JavaScript的AngularJS库编写hello world的方法
Jun 23 #Javascript
You might like
smarty的保留变量问题
2008/10/23 PHP
php缓存技术详细总结
2013/08/07 PHP
PHP swfupload图片上传的实例代码
2013/09/30 PHP
ThinkPHP在新浪SAE平台的部署实例
2014/10/31 PHP
php中debug_backtrace、debug_print_backtrace和匿名函数用法实例
2014/12/01 PHP
php的4种常见运行方式
2015/03/20 PHP
php自定义类fsocket模拟post或get请求的方法
2015/07/31 PHP
详解WordPress中添加和执行动作的函数使用方法
2015/12/29 PHP
laravel框架之数据库查出来的对象实现转化为数组
2019/10/23 PHP
可缩放Reloaded-一个针对可缩放元素的复用组件
2007/03/10 Javascript
jQuery 解析xml文件
2009/08/09 Javascript
比较全面的event对像在IE与FF中的区别 推荐
2009/09/21 Javascript
自定义ExtJS控件之下拉树和下拉表格附源码
2013/10/15 Javascript
node.js中的fs.writeSync方法使用说明
2014/12/15 Javascript
js简单设置与使用cookie的方法
2016/01/22 Javascript
addEventListener()与removeEventListener()解析
2017/04/20 Javascript
react-native 完整实现登录功能的示例代码
2017/09/11 Javascript
新版vue-cli模板下本地开发环境使用node服务器跨域的方法
2018/04/03 Javascript
JavaScript简易计算器制作
2020/01/17 Javascript
浅谈Vue 自动化部署打包上线
2020/06/14 Javascript
[01:34]2014DOTA2展望TI 剑指西雅图VG战队专访
2014/06/30 DOTA
python根据开头和结尾字符串获取中间字符串的方法
2015/03/26 Python
python实现寻找最长回文子序列的方法
2018/06/02 Python
Python3实现的爬虫爬取数据并存入mysql数据库操作示例
2018/06/06 Python
Python for循环中的陷阱详解
2018/07/13 Python
css3 transform 3d 使用css3创建动态3d立方体(html5实践)
2013/01/06 HTML / CSS
HTML5的语法变化介绍
2013/08/13 HTML / CSS
荷兰最大的多品牌男装连锁店:Adam Brandstore
2019/12/31 全球购物
物业门卫岗位职责
2013/12/28 职场文书
英文商务邀请信
2014/01/22 职场文书
中药专业自荐信范文
2014/03/18 职场文书
中考标语大全
2014/06/05 职场文书
小区门卫岗位职责范本
2014/08/24 职场文书
区域销售经理岗位职责
2015/04/02 职场文书
Go缓冲channel和非缓冲channel的区别说明
2021/04/25 Golang
python实现会员信息管理系统(List)
2022/03/18 Python