详细解读JavaScript的跨浏览器事件处理


Posted in Javascript onAugust 12, 2015

一.关于获取事件对象

FF有点倔强,只支持arguments[0],不支持window.event。这次真的不怪IE,虽然把event作为window的属性不合规范,但大家都已经默许这个小问题存在了,只有FF这么多年了还是特立独行。所以,跨浏览器的事件对象获取有以下两种方式:

带参的:

getEvent : function(event){
  return event ? event : window.event;
  //return event || window.event;//或者更简单的方式
}

无参的:

function getEvent() {
  return arguments[0] ? arguments[0] : window.event;
  //return arguments[0] || window.event;//或者更简单的方式
}

需要特别说明一种方式:HTML的DOM0级方式 + 带参的事件处理器,如下:

function handler(event){
  //do something
}
<!-- HTML的DOM0级方式 -->
<button id="btn" onclick="handler(event);">按钮</button>

上面这种方式是全浏览器兼容的,但依赖HTML的DOM0级方式的缺点很明显,所以没能成为像前两种那样的主流方法,而JS的DOM0级方式 + 带参的事件处理器,如下:

function handler(event){
  //do something
}
btn.onclick = handler;//JS的DOM0级方式
//btn.onclick = function(event){/*do something*/}//或者匿名函数,效果同上

这种方式不是全浏览器兼容的,[IE8-]不支持,IE9+未知,FF,Chrome支持。一直以为HTML的DOM0级事件处理和JS的DOM0级事件处理是等价的,现在做了很多实验才发现二者是有区别的

二.关于获取事件源

event.srcElement是[IE8-]唯一的方式,IE9+未知,其它浏览器都支持标准的event.target方式

三.关于阻止事件默认行为

event.preventDefault()是标准方法,但[IE8-]不支持,IE自己的方式是event.returnValue = false;

四.关于停止事件传播

event.stopPropagation()是标准方法,IE又有意见了,他要这么玩:event.cancelBubble = true;这里需要特别注意了,因为cancel是属性而不是方法,与标准相差甚远,容易记错

五.关于事件处理器的添加和移除

DOM0级方式

ele.onclick = handler;ele.onclick=null;最古老的一种方式

优点:全浏览器兼容

缺点:同一事件只能绑定/解绑一个事件处理器

DOM2级方式

ele.add/removeEventListener(eventType, handler, catch);

和IE方式:ele.attach/detachEvent(‘on'+eventType, handler);

优点:支持绑定/解绑多个事件处理器

缺点:需要做兼容性判断。需要注意的是:标准方式中最后一个参数表示是否在事件捕获阶段绑定/解绑,IE不支持事件捕获,所以也就没有第三个参数了

注意:IE方式不仅方法名与标准不同,参数中事件类型还要加上on,否则绑定无效但不报错

六.跨浏览器的事件处理

//跨浏览器的事件处理器添加方式
var EventUtil = {
  addHandler : function(elem, type, handler){
    if(elem.addEventListener){
      elem.addEventListener(type, handler, false);
    }
    else if(elem.attachEvent){
      elem.attachEvent("on" + type, handler);//添加多个同一类型的handler时,IE方式的规则是最后添加的最先触发
    }
    else{
      if(typeof elem["on" + type] === 'function'){
        var oldHandler = elem["on" + type];
        elem["on" + type] = function(){
          oldHandler();
          handler();
        }
      }
      else{
        elem["on" + type] = handler;//支持添加多个事件处理器
      }
    }
  },

  getEvent : function(event){
    return event ? event : window.event;
  },

  getTarget : function(event){
    return event.target || event.srcElement;
  },

  preventDefault : function(event){
    if(event.preventDefault){
      event.preventDefault();
    }
    else{
      event.returnValue = false;
    }
  },

  removeHandler : function(elem, type, handler){
    if(elem.removeEventListener){
      elem.removeEventListener(type, handler, false);
    }
    else if(elem.detachEvent){
      elem.detachEvent("on" + type, handler);
    }
    else{
      elem["on" + type] = null;//不支持移除单一事件处理器,只能全部移除
    }
  },

  stopPropagation : function(event){
    if(event.stopPropagation){
      event.stopPropagation();
    }
    else{
      event.cancelBubble = true;
    }
  },

  getRelatedTarget : function(event){
    if(event.relatedTarget){
      return event.relatedTarget;
    }
    else if(event.toElement && event.type == "mouseout"){
      return event.toElement;
    }
    else if(event.fromElement && event.type == "mouseover"){
      return event.fromElement;
    }
    else{
      return null;
    }
  },

  /*IE8点击左键和中键都是0;FF无法识别中键;Chrome正常*/
  getButton : function(event){//返回0,1,2 - 左,中,右
    if(document.implementation.hasFeature("MouseEvents", "2.0")){
      return event.button;
    }
    else{
      switch(event.button){
        case 0:case 1:case 3:case 5:case 7:
          return 0;
          break;
        case 2:case 6:
          return 2;
          break;
        case 4:
          return 1;
          break;
        default:
          break;
      }
    }
  },

  /*只能检测keypress事件,返回值等于将要显示的字符编码*/
  /*IE和Chrome只有能显示的字符键才触发,FF其它键也能触发,返回值为0*/
  getCharCode : function(event){
    if(typeof event.charCode == "number"){
      return event.charCode;
    }
    else{
      return event.keyCode;
    }
  }
};

综合示例

如果项目中没有使用诸如 jQuery 之类的库,如何方便地为元素绑定事件,并兼容各种浏览器呢?下面这个简单的 Utility 应该可以考虑。

var eventUtility = {
  addEvent : function(el, type, fn) {
    if(typeof addEventListener !== "undefined") {
      el.addEventListener(type, fn, false);
    } else if(typeof attachEvent !== "undefined") {
      el.attachEvent("on" + type, fn);
    } else {
      el["on" + type] = fn;
    }
  },

  removeEvent : function(el, type, fn) {
    if(typeof removeEventListener !== "undefined") {
      el.removeEventListener(type, fn, false);
    } else if(typeof detachEvent !== "undefined") {
      el.detachEvent("on" + type, fn);
    } else {
      el["on" + type] = null;
    }
  },

  getTarget : function(event) {
    if(typeof event.target !== "undefined") {
      return event.target;
    } else {
      return event.srcElement;
    }
  },

  preventDefault : function(event) {
    if(typeof event.preventDefault !== "undefined") {
      event.preventDefault();
    } else {
      event.returnValue = false;
    }
  }
};

使用方法示例:

var eventHandler = function(evt) {
  var target = eventUtility.getTarget(evt),
    tagName = target.tagName;

  if(evt.type === "click") {
    if(tagName === "A" || tagName === "BUTTON") {
      alert("You clicked on an A element, and the innerHTML is " + target.innerHTML + "!");
      eventUtility.preventDefault(evt);
    }
  } else if(evt.type === "mouseover" && tagName === "A") {
    alert("mouseovered " + target.innerHTML);
  }

};

eventUtility.addEvent(document, "click", eventHandler);
eventUtility.addEvent(document, "mouseover", eventHandler);

eventUtility.removeEvent(document, "mouseover", eventHandler);

Javascript 相关文章推荐
javascript 操作文件 实现方法小结
Jul 02 Javascript
javascript:window.open弹出窗口的位置问题
Mar 18 Javascript
jQuery中document与window以及load与ready 区别详解
Dec 29 Javascript
jQuery中not()方法用法实例
Jan 06 Javascript
jQuery zclip插件实现跨浏览器复制功能
Nov 02 Javascript
AngularJS监听路由的变化示例代码
Sep 23 Javascript
微信小程序 石头剪刀布实例代码
Jan 04 Javascript
three.js快速入门【推荐】
Jan 21 Javascript
Javascript 详解封装from表单数据为json串进行ajax提交
Mar 29 Javascript
微信小程序 登录的简单实现
Apr 19 Javascript
jQuery 实时保存页面动态添加的数据的示例
Aug 14 jQuery
详解js获取video任意时间的画面截图
Apr 17 Javascript
基于jQuery实现动态数字展示效果
Aug 12 #Javascript
jQuery中$.ajax()和$.getJson()同步处理详解
Aug 12 #Javascript
深入解读JavaScript中的Hoisting机制
Aug 12 #Javascript
Jquery代码实现图片轮播效果(一)
Aug 12 #Javascript
javascript表单验证大全
Aug 12 #Javascript
JavaScript实现动态删除列表框值的方法
Aug 12 #Javascript
jQuery实现文件上传进度条特效
Aug 12 #Javascript
You might like
ThinkPHP模板IF标签用法详解
2014/07/01 PHP
浅析PHP中Session可能会引起并发问题
2015/07/23 PHP
php实现无限级分类查询(递归、非递归)
2016/03/10 PHP
如何直接访问php实例对象中的private属性详解
2017/10/12 PHP
PHP实现SMTP邮件的发送实例
2018/09/27 PHP
掌握PHP垃圾回收机制详解
2019/03/13 PHP
php输出控制函数和输出函数生成静态页面
2019/06/27 PHP
利用PHP内置SERVER开启web服务(本地开发使用)
2021/03/09 PHP
PHP高并发和大流量解决方案整理
2021/03/09 PHP
js过滤特殊字符输入适合输入、粘贴、拖拽多种情况
2014/03/22 Javascript
javascript原生和jquery库实现iframe自适应高度和宽度
2014/07/18 Javascript
浅谈jQuery中对象遍历.eq().first().last().slice()方法
2014/11/26 Javascript
JavaScript限定图片显示大小的方法
2015/03/11 Javascript
JavaScript制作windows经典扫雷小游戏
2015/03/31 Javascript
简单的JS时钟实例讲解
2016/01/13 Javascript
Vue.js学习示例分享
2017/02/05 Javascript
jQuery滚动监听实现商城楼梯式导航效果
2017/03/06 Javascript
angularjs实现天气预报功能
2020/06/16 Javascript
Vue多系统切换实现方案
2018/06/05 Javascript
微信小程序实现顶部导航特效
2019/01/28 Javascript
小程序接口的promise化的实现方法
2019/12/11 Javascript
Vue学习之常用指令实例详解
2020/01/06 Javascript
Vue 组件复用多次自定义参数操作
2020/07/27 Javascript
[01:44]《为梦想出发》—联想杯DOTA2完美世界全国高校联赛
2015/09/30 DOTA
[02:44]重置世界,颠覆未来——DOTA2 7.23版本震撼上线
2019/12/01 DOTA
python实现类似ftp传输文件的网络程序示例
2014/04/08 Python
python实现的守护进程(Daemon)用法实例
2015/06/02 Python
在Python程序中操作MySQL的基本方法
2015/07/29 Python
python实现用户管理系统
2018/01/10 Python
Python requests库用法实例详解
2018/08/14 Python
python爬取基于m3u8协议的ts文件并合并
2019/04/26 Python
Java程序开发中如何应用线程
2016/03/03 面试题
路政管理专业推荐信
2013/11/11 职场文书
财产公证书样本
2014/04/04 职场文书
财务内勤岗位职责
2014/04/17 职场文书
社区党建工作方案
2014/06/10 职场文书