JavaScript中事件处理

简介: 不需要使用window.addEventListener或document.all来进行检测浏览器,应该使用能力检测;

先看看下面一道题目,请评价以下代码并给出改进意见:


if (window.addEventListener) {//标准浏览器
  var addListener = function(el, type, listener, useCapture) {
    el.addEventListener(type, listener, useCapture);
  };
} else if (document.all) {//IE
  addListener = function(el, type, listener) {
    el.attachEvent("on" + type, function() {
      listener.apply(el);
    });
  }
}


1)不应该在if和else语句中声明addListener函数,应该先声明;

2)不需要使用window.addEventListener或document.all来进行检测浏览器,应该使用能力检测;

3)attachEvent在IE中有this指向问题,会指向window,虽然上面的代码做了指向处理,但是匿名函数不能做detachEvent解绑

改进后的代码稍后加上。

 

一、冒泡与捕获


使用过addEventListener方法的会发现最后一个参数“useCapture”,用于控制是捕获还是冒泡。

何为冒泡、捕获,请看下面的例子:查看在线代码,在线代码中用了三层。


<div id="click1">
  <div id="click2">事件</div>
</div>


1)Netscape主张元素1的事件首先发生,这种事件发生顺序被称为捕获型,如下图所示:


               | |
---------------| |-----------------
| click1       | |                |
|   -----------| |-----------     |
|   |click2    \ /          |     |
|   -------------------------     |
|        Event CAPTURING          |
-----------------------------------


2)微软则保持元素2具有优先权,这种事件顺序被称为冒泡型,如下图所示:


               / \
---------------| |-----------------
| click1       | |                |
|   -----------| |-----------     |
|   |click2    | |          |     |
|   -------------------------     |
|        Event BUBBLING           |
-----------------------------------


3)W3C选择了一个择中的方案。任何发生在w3c事件模型中的事件,首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段,如下图所示:


               | |  / \
---------------| |--| |------------
| click1       | |  | |           |
|   -----------| |--| |------     |
|   |click2    \ /  | |     |     |
|   -------------------------     |
|      W3C event model            |
-----------------------------------


4)阻止冒泡,很多时候是不想触发父级的相同事件的,那么就需要阻止这种行为。

W3C方:event.stopPropagation()。(chrome、firefox、safrai等)

IE方:event.cancelBubble设置为true。

经过我的在线测试,stopPropagation这个方法不能阻止捕获。

这里顺带说下阻止默认事件的方法,何为默认事件?就比如a标签设置了href,就会做跳转,这里阻止它跳转。

W3C方:event.preventDefault(),但只有event的cancelable属性为true时才能使用。

IE方:event.returnValue设置为false。

 

二、事件系统


浏览器提供了3种层次的API。

1)最原始的是写在元素标签内

2)以el.onXXX=function绑定的方式,通称为DOM0事件系统。

3)一个元素的同一类型事件可以绑定多个回调,通称为DOM2事件系统。


IE与W3C依旧不同,语法如下:


序号 操作与对象 IE方 W3C方

1

绑定事件

el.attachEvent("on"+type, callback) el.addEventListener(type,callback,[useCapture])

2

卸载事件

el.detachEvent("on"+type,callback) el.removeEventListener(type,callback,[useCapture])
3 创建事件 document.createEventObject()

document.createEvent(types) 创建事件(过时

event.initEvent() 初始化事件(过时

new Event(types)

4

派发事件

el.fireEvent(type,event) el.dispatchEvent(event)
5 event属性 srcElement:等于target,默认目标

currentTarget:其事件处理程序当前正处理事件的元素

target:事件的目标

6 event方法

returnValue:等于preventDefault()

cancelBubble:设为true等于stopPropagation()

preventDefault():阻止默认行为

stopPropagation():阻止冒泡

7

type

被触发的事件类型,需要“on”前缀 被触发的事件类型

8

事件执行顺序

与添加顺序相反 与添加顺序一致
9

匿名函数

无法移除 无法移除

10

this

window 当前绑定的元素

 


注意第8点,在测试代码中,我绑定了两个相同的“click”事件, 查看在线完整代码


var func1 = function(e) {
  alert(1); //测试执行顺序
};
var func2 = function(e) {
  alert(2);
};
var type = 'click';
bind(ele, type, func1);
bind(ele, type, func2);

 

注意上面的第9点和第10点,上面那道题目中要解决的就是这个问题。下面的代码是个片段,查看在线完整代码


var bind = function(ele, type, callback) {
  if (!ele[type + "event"]) {
    ele[type + "event"] = {}; //声明一个空对象,缓存事件
  }
  var name = callback.toString();
  if (!ele[type + "event"][name]) {
    var handler = function(event) {
      //可以做更多event封装操作
      var ev = event || window.event;
      callback.call(ele, ev);
    };
    ele[type + "event"][name] = handler; //做个临时变量
  }
  if (ele.addEventListener) {
    ele.addEventListener(type, handler, false);
  } else if (ele.attachEvent) {
    ele.attachEvent('on' + type, handler);
  }
}
var unbind = function(ele, type, callback) {
  var handler = ele[type + "event"][callback.toString()]; //读取临时变量
  if (ele.removeEventListener) {
    ele.removeEventListener(type, handler);
  } else if (ele.detachEvent) {
    ele.detachEvent('on' + type, handler);
  }
}

上面的代码还比较粗糙,仅仅是用于演示一下。方法有很多,自己可以揣摩。

我看到网上有人直接不用attachEvent,将相应的事件保存在一个数组中,当detachEvent的时候做splice数组的操作。

大家也可以参考下一些成熟的类库,例如jQuery1.8.3版本,2642行的event.add封装,2757行的event.remove封装,3485行的on封装。

也可以参考Dean Wdwards写的addEvent方法,这是Prototype时代早期出现的一个事件系统,jQuery事件系统的源头。


相关文章
|
4月前
|
Web App开发 JavaScript 前端开发
javascript onkeydown事件
javascript onkeydown事件
|
6月前
|
JavaScript 前端开发
js事件队列
js事件队列
155 55
|
4月前
|
JavaScript
js两种移除事件的方法
js两种移除事件的方法
57 3
|
26天前
|
JavaScript 前端开发 测试技术
盘点原生JavaScript中直接触发事件的方式
本文全面探讨了原生JavaScript中触发事件的多种方式,包括`dispatchEvent`、`Event`构造函数、`CustomEvent`构造器、直接调用事件处理器以及过时的`createEvent`和`initEvent`方法。通过技术案例分析,如模拟点击事件、派发自定义数据加载事件和实现提示框系统,帮助开发者掌握这些方法在实际开发中的应用,提升灵活性与兼容性。
35 3
|
5月前
|
JavaScript 前端开发
JavaScript 事件
JavaScript 事件
50 2
|
6月前
|
JavaScript 前端开发
JavaScript 事件的绑定
JavaScript 事件的绑定
62 0
|
3月前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
87 5
|
4月前
|
存储 JavaScript 前端开发
js事件队列
【10月更文挑战第15天】
79 6
|
5月前
|
JavaScript 前端开发
JavaScript HTML DOM 事件
JavaScript HTML DOM 事件
36 5
|
5月前
|
监控 JavaScript 前端开发

热门文章

最新文章

  • 1
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    23
  • 2
    Node.js 中实现多任务下载的并发控制策略
    32
  • 3
    【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
    25
  • 4
    【JavaScript】深入理解 let、var 和 const
    48
  • 5
    【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
    44
  • 6
    【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
    52
  • 7
    【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
    55
  • 8
    如何通过pm2以cluster模式多进程部署next.js(包括docker下的部署)
    71
  • 9
    【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
    55
  • 10
    JavaWeb JavaScript ③ JS的流程控制和函数
    62