您现在的位置: 万盛学电脑网 >> 程序编程 >> 脚本专题 >> javascript >> 正文

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

作者:佚名    责任编辑:admin    更新时间:2022-06-22

  浏览器的嗅探现在已经不推荐了,但在某些场合还是需要的。比如一些统计脚本。在标准浏览器里,提供了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写了一篇文章,来判断浏览器对某种事件的支持。里面给出的实现如下:

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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.

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $.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模块

? 1 2 3 4 5 6 7 8 9 10 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

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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元素都转换失败