前端面试必考:事件委托

先看几道面试题

  1. 描述下js里面的事件流
  2. 默认情况下,事件是在冒泡阶段执行还是捕获阶段执行
  3. 请简要说明事件委托原理和使用场景
  4. 手写原生js实现事件代理,注意浏览器兼容

如果上面的面试题,您不能很顺利的作答,那么希望这篇文件对您能有一些帮助。如果出现错误,请您及时指正,谢谢。

什么是事件委托

事件委托也叫事件代理,《Javascript高级程序设计》中写道:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

想要理解事件委托,需要先理解js事件流。


js事件流

图为事件流的全过程,从图中我们可以看出:

  • 一个完整的事件流是从window开始,最后回到window的一个过程
  • 事件流被分为3个阶段:1-5捕获阶段,5-6:目标阶段,6-10:冒泡阶段

观察代码,并说出打印结果

html

<body>
    <div style="height: 100px;background: grey;"></div>
</body>

js

var oDiv = document.querySelector(‘#div‘);
oDiv.addEventListener(‘click‘,function(){
    console.log(‘div‘)
});
document.body.addEventListener(‘click‘,function(){
    console.log(‘body‘)
});
var oDiv = document.querySelector(‘#div‘);
oDiv.addEventListener(‘click‘,function(){
    console.log(‘div‘)
},false);
document.body.addEventListener(‘click‘,function(){
    console.log(‘body‘)
},false);
var oDiv = document.querySelector(‘#div‘);
oDiv.addEventListener(‘click‘,function(){
    console.log(‘div‘)
},true);
document.body.addEventListener(‘click‘,function(){
    console.log(‘body‘)
},true);

通过上述代码,我们发现:

  • addEventListener有3个参数:event, function, useCapture(可选)
  • useCapture为true时,事件在捕获阶段执行,打印结果为body、div
  • useCapture为false时,事件在冒泡阶段执行,打印结果为div、body
  • useCapture值不传时,事件在冒泡阶段执行,打印结果为div、body

阻止默认冒泡行为,我们可以用

ev.stopPropagation()

现在,我们认识了js事件流,接下来,说一说事件委托。


js事件委托

我们先来看一个场景:

现在有一个todo list,需要实现以下功能:

  1. 点击‘添加’按钮时,列表中新增item,内容为文本框输入内容
  2. todo Item 点击‘完成‘按钮时自动删除

我们知道的给DOM绑定事件的方法有以下几种:

嵌入DOM

例如:

<li>想你 <button onclick="complete">完成</button></li>
直接绑定
oBtn.onclick = complete
事件监听
oBtn.addEventListener(‘click‘,complete)

需求很简单,但是有两点需要注意:

  • 如果给‘完成’按钮绑定事件,因为不断有新DOM的生成,每次生成都要重新绑定,代码不便管理
  • 如果给‘完成’按钮绑定事件,则需要循环遍历每一个‘完成’按钮,不断访问DOM,按钮越多,访问次数越多,性能越低

为了解决上述两个问题,‘事件代理’便是完美的解决方案。

实现思路

将事件绑定到父元素ul上,当用户点击按钮时,通过事件流,冒泡到父元素ul,从而执行回调。

事件代理的好处

  • 只绑定一次事件,无频繁访问DOM,性能较高
  • 当有新DOM生成时,无需重复绑定事件,代码清晰简洁

现在,我们使用事件代理的方式实现上述需求,可是我应该如何判断点击的是‘完成’按钮,而不是其他元素呢?


事件对象

事件对象是在事件发生时产生,用来记录事件发生时的一些信息。

oUl.addEventListener(‘click‘,function(ev){
    var ev = ev || event;
    console.log(ev);
})

事件对象中记录了点击事件发生时的目标元素,但由于浏览器存在差异,所以兼容性的写法为:

   var origin = ev.target || ev.srcElement

手写原生js实现事件代理,浏览器兼容

function bindEvent(obj, type, fn) {
    if (obj.addEventListener) {
      obj.addEventListener(type, eventFn);
    } else {
      obj.attachEvent("on" + type, eventFn);
    }

    function eventFn(ev) {
      var ev = ev || window.event;
      var target = ev.target || ev.srcElement;
      fn && fn(target, ev)
    }
  }

原文地址:https://www.cnblogs.com/yxqd/p/10369392.html

时间: 2024-10-15 04:43:46

前端面试必考:事件委托的相关文章

JavaScript基础--------三座大山(前端面试必考)

1.原型和原型链 2.作用域和闭包 3.异步和单线程 被称为JavaScript的三座大山 原型和原型链: 在JavaScript中,数组,对象和函数被称为引用类型,他们都有一个__proto__属性,该属性是一个对象(我们称之为隐式原型) arr数组的构造函数是Array,Array构造函数中有一个prototype属性,(我们暂时称之为显式原型) arr是构造函数的实例对象,arr中的__proto__对象指向构造函数中的prototype对象 接下来是一个简单的demo 1 //创建一个构

95%的技术面试必考的JVM知识点都在这,另附加分思路!

概述:知识点汇总 jvm的知识点汇总共6个大方向:内存模型.类加载机制.GC垃圾回收是比较重点的内容.性能调优部分偏重实际应用,重点突出实践能力.编译器优化和执行模式部分偏重理论基础,主要掌握知识点. 各个部分的内容如下: 1>内存模型部分:程序计数器.方法区.堆.栈.本地方法栈的作用,保存哪些数据: 2>类加载部分:双亲委派的加载机制以及常用类加载器分别加载哪种类型的类: 3>GC部分:分代回收的思想和依据,以及不同垃圾回收算法实现的思路.适合的场景: 4>性能调优部分:常用的j

Java BAT大型公司面试必考技能视频-1.HashMap源码分析与实现

视频通过以下四个方面介绍了HASHMAP的内容 一. 什么是HashMap Hash散列将一个任意的长度通过某种算法(Hash函数算法)转换成一个固定的值. MAP:地图 x,y 存储 总结:通过HASH出来的值,然后通过值定位到这个MAP,然后value存储到这个MAP中的HASHMAP基本原理 1. KEY 是否可以为空?可以,Null当成一个Key来存储 2. 如果Hash KEY重复了会覆盖吗?会覆盖,但返回旧的值 3. HASHMAP什么时候做扩容?put 的时候,阀值高于或等于0.7

JavaScript面试问题:事件委托和this

JavaScript不仅门槛低,而且是一门有趣.功能强大和非常重要的语言.各行各业的人发现自己最混乱的选择是JavaSscript编程语言.由 于有着各种各样的背景,所以不是每个人都对JavaScript及其基本原理有广泛的认识.通常来书,除非你去参加工作面试才会去思考为什么或者怎么做, 否则JavaScript只是你工作的内容. 这个系类的目标是深入探讨JavaScript的一些概念和理论.主题来自于 Darcy Clarke的JavaScript典型面试问题列表.希望你不仅仅是为了答案而阅读

MySQL面试必考知识点:揭秘亿级高并发数据库调优与最佳实践法则

做业务,要懂基本的SQL语句: 做性能优化,要懂索引,懂引擎: 做分库分表,要懂主从,懂读写分离... 数据库的使用,是开发人员的基本功,对它掌握越清晰越深入,你能做的事情就越多. 今天我们用10分钟,重点梳理一遍以下几方面: 数据库知识点汇总: 数据库事务特性和隔离级别: 详解关系型数据库.索引与锁机制: 数据库调优与最佳实践: 面试考察点及加分项. 知识点汇总 一.数据库的不同类型 1.常用的关系型数据库 Oracle:功能强大,主要缺点就是贵 MySQL:互联网行业中最流行的数据库,这不仅

【iOS开发-34】自己主动释放池@autoreleasepool的使用注意事项以及ARC机制——面试必考内容

自己主动释放池@autorelease面试频率可能会吧release还要高. (1)在自己主动释放池@autoreleasepool{}中alloc一个对象后(如p1).仍然须要用[p1 autorelease];不过这个语句和[p1 release];不同.后者表示把p1的retainCount-1,而前者只表示把p1放到自己主动释放池中返回一个self,自己主动释放池结束销毁时,统一对里面的对象引用计数retainCount-1. (2)@autoreleasepool{}能够任意创建.也能

【iOS开发-34】自动释放池@autoreleasepool的使用注意事项以及ARC机制——面试必考内容

自动释放池@autorelease面试频率可能会吧release还要高. (1)在自动释放池@autoreleasepool{}中alloc一个对象后(如p1),仍然需要用[p1 autorelease];只是这个语句和[p1 release];不同,后者表示把p1的retainCount-1,而前者仅仅表示把p1放到自动释放池中返回一个self,自动释放池结束销毁时,统一对里面的对象引用计数retainCount-1. (2)@autoreleasepool{}可以随意创建,也可以嵌套使用.

Android面试必考基础题

(1)<必考题>请写出Android系统架构有几层,分别是哪几层? 考点:Android系统架构 答案:有四层.分别是Linux内核.本地库和Java运行时环境.应用程序框架.应用程序. (2)<必考题>请简要介绍Android的四大组件? 考点:Android四大组件 答案:Android系统有四种组件,这四种组件构成了Android应用的框架,然后由Intent联系这四种组件.Activity用来显示Android的程序界面,一个应用往往有多个界面,所以一个应用中会有多个Act

8个Python面试必考的题目,小编也被坑过 ToT

写在前面 小编学习Python已经三年多了,现在稳定在一家公司快一年了,回想起来一年以前的面试经历真的有点胆战心惊啊! 因为面试题目一不小心就会被坑啊~ 你经历过绝望么? 当你被Python面试题目坑到的时候内心真的一万个草泥马徘徊在心中啊o(╥﹏╥)o 下面小编就分享一些小编亲身经历过的一些Python神坑面试题哦~ 干货来了 1.下面这段代码的输出结果是什么?请解释. def extendList(val, list=[]): list.append(val) return list lis