分享

检测浏览器对事件不同的处理方式

 cicy000 2012-08-20

检测浏览器对事件不同的处理方式


目前西方很多WEB开发工作者对浏览器的研究几乎达到一个狂热的程度,这归根到底还是源于jQuery搞出特性侦探这个属性。但是由于浏览器内核 的不同,导致不同的浏览器对事件的处理方式是有区别的,比如在IE浏览器下是支持mouseenter与mouseleave,Opera支持右键菜单但 不允许你用contextmenu类似的API操作它,还有onbeforepaste, onbeforecut这些与input元素相关的事件,IE浏览器与WebKit支持,但FF不支持。当然还有一些像“阻止事件冒泡”以及“取消浏览器 默认行为”等,不同浏览器也有不同的处理方式,如果我们要使JavaScript在不同的浏览器下能正常处理事件代码,就要分别进行判断处理。而 jQuery类库为我们提供了屏蔽浏览器的差异的办法。

jQuery是一种让开发和设计者在他们的网页中添加交互内容的工具,它的核心命令让你在网页中定位或创建对象并对之进行操作,它事实上是一种更容易使用的JavaScript,可以不必强迫页面刷新而对页面进行各种操作。

JavaScript为设计拓宽了视野,而jQuery让这一切变得更简单。对那些通晓CSS的设计师来说,编写jQuery代码很类似,而对于那 些拥有Flash经验的设计师来说,jQuery是一种标准化的,开放的技术,它可以实现类似Flash的交互效果,让网页能够在浏览器中呈现更加多样化 的效果。

在以前javascript与DOM遍地是bug,美工主宰前端的年代,人们只有两种极端方式,用户禁止脚本运行,浏览器商狂升级(IE6之前也很 积极的)。这年头,也就Base2与Prototype2做得最好,当然dojo与YUI也不错。不过最近五年,Opera与Safari都建立了对 DOM完整的支持后,世界分两半,一半是IE浏览器统治的混乱世界,它是拥有如此丰富的私有特征,CSS表达式,HTC,CSS滤 镜,VML,userData,XML数据岛,最早的AJAX支持,以及DHTML最好的支持 API(innerHTML,innerText,outerHTML,outerText,insertAdjactentXXX,offsetXXX,clientXXX,scrollXXX,Range,designMode,sertRow 和insertCell等动态操作表格API……),难怪IE会赢的!不过IE也埋下了许多地雷,加之IE浏览器不 会像其他游览器升级那么快,许多Bug都要我们亲手修正。这么多浏览器,这么多版本,特性侦探是很有必要。现在我们看到那一套关于事件的API,基本上是 微软从桌面搬过来,后来W3C又加一大堆与DOM开头的事件,不过除了DOMMouseScroll基本没什么人用。N多事件,与逐个嗅探浏览器那样成了 个头痛的问题。

一般我们可以用for…in循环把它遍历一下,或者像以下简单地检测:

‘onclick’ in document.documentElement; // true
‘onclick2′ in document.documentElement; // false
很不幸,这不准确,因为我们可以添加一些同名的自定义属性。有人说,赶在用户添加之前检测它们,但也行不通,因此有些事件是只有特定元素才有的。

‘onreset’ in document.documentElement; // false
‘onreset’ in document.createElement(’input’); // true
在标准浏览器我们可以用setAttrubute为元素赋以已知事件名一个值,这个值会自动包装成一个函数,如果非事件名,则不会改变其类型。那么我检测它是否为函数就是!

var el = document.createElement(’div’);

el.setAttribute(’onclick’, ‘return;’);
alert(typeof el.onclick); // “function”

el.setAttribute(’onclick2′, ‘return;’);
alert(typeof el.onclick2); // “undefined”
同样很不幸,基于众所周知的原因,IE的setAttribute与W3C是有很大的差别,IE会原样输出,加之,IE不存在所谓的泛化函数(原生对象的 方法),它的API没有name,call,apply与toString,因此也无法判定它们是否为函数。综合以上两种方式,看看外国人搞出什么怪物 来……

var isEventSupported = (function(){//使用模块模式

var TAGNAMES = {//特定元素上的特定事件
’select’:'input’,'change’:'input’,
’submit’:'form’,'reset’:'form’,
‘error’:'img’,'load’:'img’,'abort’:'img’
}

function isEventSupported(eventName, element) {

element = element || document.createElement(TAGNAMES[eventName] || ‘div’);
eventName = ‘on’ + eventName;

// When using `setAttribute`, IE skips “unload”, WebKit skips “unload” and “resize”, whereas `in` “catches” those
var isSupported = (eventName in element);//DOM0

if (!isSupported) {
// if it has no `setAttribute` (i.e. doesn’t implement Node interface), try generic element
if (!element.setAttribute) {
element = document.createElement(’div’);
}
if (element.setAttribute && element.removeAttribute) {
element.setAttribute(eventName, ”);
isSupported = typeof element[eventName] == ‘function’;

// if property was created, “remove it” (by setting value to `undefined`)
if (typeof element[eventName] != ‘undefined’) {
element[eventName] = void 0;
}
element.removeAttribute(eventName);
}
}

element = null;
return isSupported;
}
return isEventSupported;
})();

<!doctype html>
<html dir=”ltr” lang=”zh-CN”>
<head id=”head”>
<meta charset=”utf-8″/>
<title>司徒正美 </title>

<script type=”text/javascript” charset=”utf-8″>
window.onload = function(){

var isEventSupported = (function(){//使用模块模式

var TAGNAMES = {//特定元素上的特定事件
’select’:'input’,'change’:'input’,
’submit’:'form’,'reset’:'form’,
‘error’:'img’,'load’:'img’,'abort’:'img’
}

function isEventSupported(eventName, element) {

element = element || document.createElement(TAGNAMES[eventName] || ‘div’);
eventName = ‘on’ + eventName;

// When using `setAttribute`, IE skips “unload”, WebKit skips “unload” and “resize”, whereas `in` “catches” those
var isSupported = (eventName in element);//DOM0

if (!isSupported) {
// if it has no `setAttribute` (i.e. doesn’t implement Node interface), try generic element
if (!element.setAttribute) {
element = document.createElement(’div’);
}
if (element.setAttribute && element.removeAttribute) {
element.setAttribute(eventName, ”);
isSupported = typeof element[eventName] == ‘function’;

// if property was created, “remove it” (by setting value to `undefined`)
if (typeof element[eventName] != ‘undefined’) {
element[eventName] = void 0;
}
element.removeAttribute(eventName);
}
}

element = null;
return isSupported;
}
return isEventSupported;
})();
function w(name, element) {
document.write(name + ‘: ‘ + (
isEventSupported(name, element)
‘<span style=”background-color:green;color:white;”>true</span>’
: ‘<span style=”background-color:red;color:white;”>false</span>’
) + ‘<br>’);
}

document.write(’<pre>’ + isEventSupported + ‘</pre><br><br>’);

document.write(’<h2>Mouse events:</h2>’);

w(’click’);
w(’dblclick’);
w(’mousedown’);
w(’mouseup’);
w(’mouseover’);
w(’mousemove’);
w(’mouseout’);

document.write(’<h2>Key events:</h2>’);

w(’keypress’);
w(’keydown’);
w(’keyup’);

document.write(’<h2>HTML events</h2>’);

w(’load’);
w(’unload’, window);
w(’abort’);
w(’error’);

document.write(’<h2>View events</h2>’);

w(’resize’, window);
w(’scroll’);

document.write(’<h2>Form events:</h2>’);

w(’submit’);
w(’reset’);

document.write(’<h2>Form controls\’ events:</h2>’);

w(’select’);
w(’change’);

document.write(’<h2>Activation events:</h2>’);

w(’focus’);
w(’blur’);

document.write(’<h2>MSHTML DOM events:</h2>’);

w(’cut’);
w(’copy’);
w(’paste’);
w(’beforecut’);
w(’beforecopy’);
w(’beforepaste’);
w(’afterupdate’);
w(’beforeupdate’);
w(’cellchange’);
w(’dataavailable’);
w(’datasetchanged’);
w(’datasetcomplete’);
w(’errorupdate’);
w(’rowenter’);
w(’rowexit’);
w(’rowsdelete’);
w(’drag’);
w(’dragstart’);
w(’dragenter’);
w(’dragover’);
w(’dragleave’);
w(’dragend’);
w(’drop’);
w(’selectstart’);
w(’mouseenter’);
w(’mouseleave’);
w(’activate’);
w(’beforeactivate’);
w(’deactivate’);
w(’beforedeactivate’);
w(’focusin’);
w(’focusout’);
w(’stop’, document);
w(’readystatechange’);
w(’beforeprint’, document.body);
w(’afterprint’, document.body);
w(’beforeunload’, window);

document.write(’<h2>Unexistent (most likely) events:</h2>’);

w(’click2′);
w(’foobarbaz’);

document.write(’<h2>Unexistent in Opera <=10a</h2>’);

w(’contextmenu’);

document.write(’<h2>iPhone touch/gesture events</h2>’);

w(’touchstart’);
w(’touchend’);
w(’touchmove’);
w(’touchcancel’);

document.write(’<br>’);

w(’gesturestart’);
w(’gesturechange’);
w(’gestureend’);

document.write(’<h2>HTML5 events</h2>’);

w(’hashchange’, document.body);
w(’online’, document.body);
w(’offline’, document.body);
w(’message’, window);
w(’undo’, document.body);
w(’redo’, document.body);
w(’storage’, window);
w(’popstate’, window);

w(’canplay’, document.createElement(’video’));
w(’seeking’, document.createElement(’video’));
w(’seekend’, document.createElement(’video’));

document.write(’<h2>Proprietary</h2>’);

w(’pageshow’, window);
w(’pagehide’, window);

};
</script>

</head>
<body>

</body>
</html>

连HTML5与iPhone touch的一些专有事件也能检测到。

在jQuery1.4α2中也支持这种特性侦探了,不过用的是早期版本,不如上面写出来的那个!

//jQuery1.4α2
var eventSupported = function( eventName ) {
var el = document.createElement(”div”);
eventName = “on” + eventName;

var isSupported = (eventName in el);
if ( !isSupported ) {
el.setAttribute(eventName, “return;”);
isSupported = typeof el[eventName] === “function”;
}
el = null;

return isSupported;
};
在未来jQuery技术方面,如果我们无法摆脱那些旧浏览器的话,事情可能没多少改变,不过,即使现在,在那些更好的浏览器身上,我们也已经看到一些令人振奋的东西,我期待看到一些全新的东西。

Webkit引擎开发团队已经做在CSS动画方面做了很多工作,他们甚至将触角伸向图形硬件来实现炫目的视觉效果。Firefox, Safari, and Chrome 正在 JavaScript引擎方面你追我赶,而众多JavaScript 库也在性能上大幅提升。我们会开到越来越多的 HTML 5元素的使用,如 Canvas, 音频,视频。Web 字体方面也将更加完善,不管从技术方面还是版权方面。可以肯定的是,未来的Web会让人惊异。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多