JS事件处理程序中的event

目录

Event对象

获取event对象

隐藏在监听函数中的"event"

event. preventDefault()

event.stopPropagation() & event.stopImmediatePropagation()

1. event.stopPropagation() 方法

2. stopImmediatePropagation()方法 

event.target & event.currentTarget

事件代理


Event对象

Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。

事件通常与函数结合使用,函数不会在事件发生前被执行!

当一个事件发生的时候,和当前这个对象发生的这个事件有关的一些详细信息(包括导致事件的元素、事件的类型、以及其它与特定事件相关的信息等。这个对象是在执行事件时,浏览器通过函数传递过来的。)都会被临时保存到一个指定的地方——event对象,供我们在需要的时候调用

获取event对象

在 W3C 规范中,event 对象是随事件处理函数传入的,Chrome、FireFox、Opera、Safari、IE9.0及其以上版本都支持这种方式;但是对于 IE8.0 及其以下版本,event 对象必须作为 window 对象的一个属性。

IE、Chrome:event是一个内置的全局对象

标准下/FF:事件对象是通过事件函数的第一个参数传入(如果一个函数是被事件调用的,那么这个函数定义的第一个参数就是事件对象)

如何处理兼容性:

document.onclick = function  fn(event){
   var ev = window.event||event;
   alert('处理兼容');
}

隐藏在监听函数中的"event"

当监听的事件发生时,浏览器会去执行我们通过addEventListener()注册的事件处理程序函数。

这个时候,EventListener 会去创建一个「事件对象」 (Event Object),里面包含了所有与这个事件相关的属性,并且以「参数」的形式传给我们的处理程序函数:

<button id="btn">Click</button>
......
var btn = document.getElementById('btn');

// 参数 e 就是上面所说的事件对象 
// 因为是参数,当然可以自己定名称
btn.addEventListener('click', function(e){
  console.log(e);
}, false);

当点击<button>后,可以从console看到event对象中提供了这么多东西:

像是

  • type : 表示事件的名称
  • target : 表示触发事件的元素
  • bubbles:表示这事件是否是在「冒泡」阶段触发( truefalse)
  • pageXpageY:表示事件触发时,鼠标座标在网页的相对位置

其余的属性这里就不一一介绍,不过要注意的是,每个「事件对象」所提供的属性都会根据触发的事件而稍微不同。

event. preventDefault()

HTML中部分元素会有默认行为,像是<a>标签默认页面跳转或是锚点定位,或是表单的submit等等...,

如果我们需要在这些元素上绑定事件,那么适当地取消它们的默认行为就是很重要的一件事。

比如,有一个通往baidu的链接<a>:

<a id="link" href="https://www.baidu.com">百度</a>

假设今天点击这个link时,我希望浏览器执行console.log('米淇淋你好帅!');那么根据先前所说,我可以先注册click事件:

var link = document.querySelector('#link');

link.addEventListener('click', function (e) {
  console.log('米淇淋你好帅!');
}, false);

结果你却发现,即便我们在<a>中去注册了click事件,但是当我点击这个link的时候,浏览器开始会console.log出"米淇淋你好帅!",但最后baidu的网页依旧会覆盖我想要的内容。

可是我希望执行的是console.log('米淇淋你好帅!');而不是直接把我带偏了去到baidu的网站,那么我们该怎么做,才能避免呢?

这时候如果调用event.preventDefault()方法,默认事件行为将不再触发

var link = document.querySelector('#link');

// 在 事件处理函数中 加上 e.preventDefault();
link.addEventListener('click', function (e) {
  e.preventDefault();
  console.log('米淇淋你好帅!');
}, false);

这个时候,再试着点击link一次,你会发现浏览器默认的跳转页面的行为不见了,console.log('米淇淋你好帅!');也可顺利执行啦哈哈。

但要注意的是,event.preventDefault()并不会阻止事件向上传递(即事件冒泡) 。

另外,值得一提的是,下面这样设置也可以让a标签仅仅当做一个普通的按钮,点击实现一个功能,不想页面跳转,也不想锚点定位:

<a href="javascript:;">链接</a>

此外,在事件处理函数的最后加上return false;也会有event.preventDefault()的效果,但切记不可以加在前面,若是加在前面事件处理函数就直接gg了。

event.stopPropagation() & event.stopImmediatePropagation()

1. event.stopPropagation() 方法

阻止事件向上冒泡传递,阻止任何父事件处理程序被执行

接下来我们看个例子:

<div>
  <div id="parent">
    父元素
    <div id="child">子元素</div>
  </div>
</div>
......
var parent = document.getElementById('parent');
var child = document.getElementById('child');

child.addEventListener('click', function () {
  console.log('child bubbling');
}, false);

parent.addEventListener('click', function () {
  console.log('parent bubbling');
}, false);

document.body.addEventListener('click', function () {
  console.log('body bubbling');
}, false);

document.documentElement.addEventListener('click', function () {
  console.log('html bubbling');
}, false);

document.addEventListener('click', function () {
  console.log('document bubbling');
}, false);

window.addEventListener('click', function () {
  console.log('window bubbling');
}, false);

当我点击的是「子元素」的时候,通过console.log可以观察到事件触发的顺序为:

child bubbling
parent bubbling
body bubbling
html bubbling
document bubbling
window bubbling

而如果在「子元素」中加入event.stopPropagation() 方法,其余保持原样的话:

child.addEventListener('click', function (e) {
  console.log('child bubbling');
  e.stopPropagation();
}, false);

再次点击「子元素」,则只出现:

child bubbling

其余父事件不会触发,即event.stopPropagation() 方法阻止了事件向上冒泡传递,阻止任何父事件处理程序被执行。

2. stopImmediatePropagation()方法 

既能阻止事件向父元素冒泡,也能阻止元素同事件类型的其它监听器被触发。而 stopPropagation 只能实现前者的效果。

我们来看个例子:

<body>
  <button id="btn">click me to stop propagation</button>
</body>
......
var btn = document.querySelector('#btn');

btn.addEventListener('click', function(e) {
  console.log('btn click 1');
  //e.stopImmediatePropagation();
});

btn.addEventListener('click', function() {
  console.log('btn click 2');
});

document.body.addEventListener('click', function() {
  console.log('body click');
});

document.documentElement.addEventListener('click', function() {
  console.log('html click');
});

document.addEventListener('click', function() {
  console.log('document click');
});

window.addEventListener('click', function() {
  console.log('window click');
});

当我点击button的时候,通过console.log可以观察到事件触发的顺序为:

btn click 1
btn click 2
body click
html click
document click
window click

而如果在「btn的第一个监听函数」中加入event.stopImmediatePropagation() 方法,其余保持原样的话:

btn.addEventListener('click', function(e) {
  console.log('btn click 1');
  e.stopImmediatePropagation();
});

再次点击button,则只出现:

btn click 1

所以说,使用 stopImmediatePropagation() 方法后,点击按钮时,仅触发设置了stopImmediatePropagation() 方法的监听器,与此同时按钮的其余同类型点击事件不触发。

event.target & event.currentTarget

老实说并不能好好用文字描述这两者的区别,我们直接看个例子:

<style>
  #a{
    width: 200px;
    height: 200px;
    background: yellow       ;
  }
  #b{
    width: 150px;
    height: 150px;
    background: green;
  }
  #c{
    width: 100px;
    height: 100px;
    background: grey;
  }
  #d{
    width: 50px;
    height: 50px;
    background: black;
  }
</style>
......
<div id="a">
  <div id="b">
    <div id="c">
      <div id="d"></div>
    </div>
  </div>
</div>
......
document.getElementById('a').addEventListener('click', function(e) {
    console.log(
      'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
})
  document.getElementById('b').addEventListener('click', function(e) {
    console.log(
      'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
})
  document.getElementById('c').addEventListener('click', function(e) {
    console.log(
      'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
})
  document.getElementById('d').addEventListener('click', function(e) {
    console.log(
      'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
})

jsbin 点这里。

当我们点击最里层黑色区域的元素d的时候,会依次输出:

target:d&currentTarget:d
target:d&currentTarget:c
target:d&currentTarget:b
target:d&currentTarget:a

从输出中我们可以看到,event.target指向引起触发事件的元素,而event.currentTarget则是事件绑定的元素,只有被点击的那个目标元素的event.target才会等于event.currentTarget也就是说,event.currentTarget始终是监听事件者,而event.target是事件的真正发出者

另外,值得一提的是,function内部的this指的也就是event.currentTarget

事件代理

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件代理或叫事件委托(Event Delegation)。

具体可看我的另一篇文章 JS事件代理和事件委托

本文参考


JavaScript事件三部曲之隐藏在其中的"秘密"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值