前端-JavaScript事件与事件流疑难点

在前端面试中,我们经常会碰到解释JS中事件的问题,今天他来了··

=

=

1.什么是事件

JavaScript和HTML之间的交互是通过事件实现的。事件,就是文档或浏览器窗口发生的一些特定的交互瞬间。可以使用监听器(或事件处理程序)来预定事件,以便事件发生时执行相应的代码。通俗的说,这种模型其实就是一个观察者模式。(事件是对象主题,而这一个个的监听器就是一个个观察者)

事件三要素:
事件目标:发生的事件与之相关联或与之相关的对象
事件处理程序:处理或相应事件的函数
事件对象:与特定事件相关且包含有关该事件详细信息的对象

2.什么是事件流

事件流描述的就是从页面中接收事件的顺序。而早期的IE和Netscape提出了完全相反的事件流概念,IE事件流是事件冒泡,而Netscape的事件流就是事件捕获。

事件冒泡/事件捕获

IE提出的事件流是事件冒泡,即从下至上,从目标触发的元素逐级向上传播,直到window对象;
而Netscape的事件流是事件捕获,即从document逐级向下传播到目标元素。由于IE低版本浏览器不支持,所以很少使用事件捕获。
后来ECMAScript在DOM2中对事件流进行了进一步规范,基本上就是上述二者的结合。

DOM2级事件规定的事件流包括三个阶段:①事件捕获阶段②处于目标阶段③事件冒泡阶段

dom0级事件/dom2级事件

DOM0事件绑定的原理:给当前元素的某一私有属性(onXXX)赋值的过程;(之前属性的默认值为null,如果我们赋值了一个函数,就相当于绑定了一个方法)
当我们赋值成功(赋值一个函数),此时浏览器会把DOM元素和赋值的函数建立关联,以及建立DOM元素的行为监听,当某一行为被用户触发,浏览器会把赋值的函数执行。

DOM2事件绑定的原理:DOM2事件绑定使用的addEventListener/attachEvent方法都是在eventTarget这个内置类的原型上定义的,我们调用时,首先要通过原型链找到这个方法,然后执行完成事件绑定的效果

浏览器会给当前元素的某个事件行为开辟一个事件池(是按队列),(浏览器有一个统一的事件池,每个元素绑定的行为都放在这里,通过相关标志区分),当我们通过addEventListener/attachEvent进行事件绑定时,会把绑定的方法放在事件池中
当元素的某一行为被触发,浏览器回到对应事件池中,把当前放在事件池的所有方法按需依次执行。

3DOM事件处理

DOM节点中有了事件,那我么就需要对事件进行处理。而DOM事件处理分为4个级别:DOM0级事件处理,DOM1级事件处理,DOM2事件处理和DOM3级事件处理。
其中DOM1级事件处理标准中并没有定义相关的内容,所以没有所谓的DOM1事件处理;DOM3级事件在DOM2级事件的基础上添加了更多的事件类型。

DOM0

DOM0级事件具有极好的跨浏览器优势,会以最快的速度绑定。第一种方式是内联模型(行内绑定)。将函数名直接作为html标签中的属性值。
缺点:不符合w3c中关于内容与行为分离的基本规范。
第二种方式是脚本模型(动态绑定),通过在JS中选中某个节点,然后给节点添加onclick属性。
缺点:同一个节点只能添加一次同类型事件

DOM2

addEventListener() --添加事件侦听器
removeEventListener() – 删除事件侦听器
函数均有三个参数,
第一个参数是要处理的事件名,
第二个参数是作为事件处理程序的函数,
第三个参数是一个boolean值,默认false表示使用冒泡机制,true表示捕获机制

4事件委托

如果有多个DOM节点需要监听事件的情况下,给每个DOM绑定监听函数,会极大的影响页面的性能,因此我们通过事件委托来进行优化,事件委托利用的就是冒泡的原理。

在一次平时测试中我意外发现了这一题:
现有DOM如下(提示:事件代理)

<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
  <li>fourth</li>
  <li>fifth</li>
</ul>

为每个li使用原生DOM API绑定点击事件,要求点击first的时候弹出1,点击second的使用弹出2,点击其他的时候弹出“其他”。

本人自己解题时并没有在意到运用事件代理,然后做出了如下答案:

  window.onload = function() {
    var lis = document.getElementsByTagName("ul")[0].children;
    lis[0].onclick = function() {
      alert("first");
    }
    lis[1].onclick = function() {
      alert("second");
    }
    for(var i=2; i<lis.length; i++) {
      lis[i].onclick = function() {
        alert("other");
      }
    }
  }

虽然样式弹出没错,但是并没有用到事件委托。
正解如下:

window.onload =  function(){
        //事件代理
        var ul = document.getElementsByTagName('ul')[0];
        ul.onclick = function(event){
          var li = event.target;
          if(li.nodeName=="LI"){
            if(li.innerText=="first"){
              alert(1);
            }else if(li.innerText=="second"){
              alert(2);
            }else{
              alert('其他');
            }
          }
        }
      }

谨以此篇,记录不足

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值