treeview节点被选中的事件_JavaScript从零开始——DOM事件编程(2)

0c8efa2ecb1d4170d098462e3aa221d4.png

DOM事件发生后,会提供一个事件对象给监听函数,方便进行下一步的处理,这就是Event对象。


1 概念

浏览器原生提供一个Event对象,所有的事件都是这个对象的实例,或者说继承了Event.prototype对象。

Event对象本身就是一个构造函数,可以用来生成新的实例:

let event = new Event(type, options);

Event构造函数接受两个参数。第一个参数type是字符串,表示事件的名称;第二个参数options是一个对象,表示事件对象的配置。该对象主要有下面两个属性:

  • bubbles:布尔值,可选,默认为false,表示事件对象是否冒泡。
  • cancelable:布尔值,可选,默认为false,表示事件是否可以被取消,即能否用Event.preventDefault()取消这个事件。一旦事件被取消,就好像从来没有发生过,不会触发浏览器对该事件的默认行为。

38fb045160fa4cf67fecc5e643690c9f.png

上面代码新建一个look事件实例,然后使用dispatchEvent方法触发该事件。

注意,如果不是显式指定bubbles属性为true,生成的事件就只能在“捕获阶段”触发监听函数。

使用如下HTML:

21b4a8c8ebadbc32d8e0e9c40e5d9780.png

86dd76c8de9ba76e93725cd906be82f1.png

上面代码中,p元素发出一个click事件,该事件默认不会冒泡。div.addEventListener方法指定在冒泡阶段监听,因此监听函数不会触发。如果写成div.addEventListener('click', callback, true),那么在“捕获阶段”可以监听到这个事件。

另一方面,如果这个事件在div元素上触发:

56678a3d0e1777e03912d113b654b7e9.png

那么,不管div元素是在冒泡阶段监听,还是在捕获阶段监听,都会触发监听函数。因为这时div元素是事件的目标,不存在是否冒泡的问题,div元素总是会接收到事件,因此导致监听函数生效。

2 实例属性

2.1 Event.bubbles,Event.eventPhase

Event.bubbles属性返回一个布尔值,表示当前事件是否会冒泡。该属性为只读属性,一般用来了解 Event 实例是否可以冒泡。前面说过,除非显式声明,Event构造函数生成的事件,默认是不冒泡的。

Event.eventPhase属性返回一个整数常量,表示事件目前所处的阶段。该属性只读:

let phase = event.eventPhase;

Event.eventPhase的返回值有四种可能:

  • 0,事件目前没有发生。
  • 1,事件目前处于捕获阶段,即处于从祖先节点向目标节点的传播过程中。
  • 2,事件到达目标节点,即Event.target属性指向的那个节点。
  • 3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程中。

2.2 Event.cancelable,Event.cancelBubble,event.defaultPrevented

Event.cancelable属性返回一个布尔值,表示事件是否可以取消。该属性为只读属性,一般用来了解 Event 实例的特性。

大多数浏览器的原生事件是可以取消的。比如,取消click事件,点击链接将无效。但是除非显式声明,Event构造函数生成的事件,默认是不可以取消的。

51e95be8784f5e7a8ea6d6989b522bc7.png

Event.cancelable属性为true时,调用Event.preventDefault()就可以取消这个事件,阻止浏览器对该事件的默认行为。

如果事件不能取消,调用Event.preventDefault()会没有任何效果。所以使用这个方法之前,最好用Event.cancelable属性判断一下是否可以取消:

function preventEvent(event) {
  if (event.cancelable) {
    event.preventDefault();
  } else {
    console.warn(`This event couldn't be canceled.`);
    console.dir(event);
  }
}

Event.cancelBubble属性是一个布尔值,如果设为true,相当于执行Event.stopPropagation(),可以阻止事件的传播。

Event.defaultPrevented属性返回一个布尔值,表示该事件是否调用过Event.preventDefault方法。该属性只读:

if (event.defaultPrevented) {
  console.log('Event canceled');
}

2.3 Event.currentTarget,Event.target

事件发生以后,会经过捕获和冒泡两个阶段,依次通过多个 DOM 节点。因此,任意时点都有两个与事件相关的节点,一个是事件的原始触发节点(Event.target),另一个是事件当前正在通过的节点(Event.currentTarget)。前者通常是后者的后代节点。

Event.currentTarget属性返回事件当前所在的节点,即事件当前正在通过的节点,也就是当前正在执行的监听函数所在的那个节点。随着事件的传播,这个属性的值会变。

Event.target属性返回原始触发事件的那个节点,即事件最初发生的节点。这个属性不会随着事件的传播而改变。

事件传播过程中,不同节点的监听函数内部的Event.targetEvent.currentTarget属性的值是不一样的。

使用如下HTML

a9c50effb16a85d74c2603d9252551ac.png

f0b98a5fb5f53f8fdeb83e38d41fcca1.png
箭头有点丑,手绘的,见谅哈哈

上面代码中,<em><p>的子节点,点击<em>或者点击<p>,都会导致监听函数执行。这时,e.target总是指向原始点击位置的那个节点,而e.currentTarget指向事件传播过程中正在经过的那个节点。由于监听函数只有事件经过时才会触发,所以e.currentTarget总是等同于监听函数内部的this

也就是说,点击 Click 的时候,this 等于 e.currentTarget,也等于 e.target,返回两个true;而点击 Here 的时候,this 是不等于 e.target 的,故此会返回一个false

2.4 Event.type

Event.type属性返回一个字符串,表示事件类型。事件的类型是在生成事件的时候指定的。该属性只读:

32ca2ec54d74f80efad684d43463747b.png

2.5 Event.timeStamp

Event.timeStamp属性返回一个毫秒时间戳,表示事件发生的时间。它是相对于网页加载成功开始计算的:

221700d00b291223179cbfe1affccc5c.png

它的返回值有可能是整数,也有可能是小数(高精度时间戳),取决于浏览器的设置。

下面是一个计算鼠标移动速度的例子,显示每秒移动的像素数量:

let previousX, previousY, previousT;

window.addEventListener('mousemove', e => {
    if (previousX !== undefined && 
        previousY !== undefined && 
        previousT !== undefined) {
        let deltaX = e.screenX - previousX;
        let deltaY = e.screenY - previousY;
        let deltaD = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
        
        let deltaT = e.timeStamp - previousT;
        console.log(deltaD / deltaT * 1000);
    }
    
    previousX = e.screenX;
    previousY = e.screenY;
    previousT = e.timeStamp;
});

d5ebaff0b3f68f098e914a6b863092c0.png
由于这个事件记录的内容太多,这里仅仅是一个示意

2.6 Event.isTrusted

Event.isTrusted属性返回一个布尔值,表示该事件是否由真实的用户行为产生。比如,用户点击链接会产生一个click事件,该事件是用户产生的;Event构造函数生成的事件,则是脚本产生的。

f0ef04cd2237df2ae52cac8580c7e1d5.png

上面代码中,ev对象是脚本产生的(前文用 new Event('foo') 生成的),所以isTrusted属性返回false

2.7 Event.detail

Event.detail属性只有浏览器的 UI (用户界面)事件才具有。该属性返回一个数值,表示事件的某种信息。具体含义与事件类型相关。比如,对于clickdblclick事件,Event.detail是鼠标按下的次数(1表示单击,2表示双击,3表示三击);对于鼠标滚轮事件,Event.detail是滚轮正向滚动的距离,负值就是负向滚动的距离,返回值总是3的倍数:

5e80dec52637a5e150555e0ae43f82da.png

3 实例方法

3.1 Event.preventDefault()

Event.preventDefault方法取消浏览器对当前事件的默认行为。比如点击链接后,浏览器默认会跳转到另一个页面,使用这个方法以后,就不会跳转了;再比如,按一下空格键,页面向下滚动一段距离,使用这个方法以后也不会滚动了。该方法生效的前提是,事件对象的cancelable属性为true,如果为false,调用该方法没有任何效果。

注意,该方法只是取消事件对当前元素的默认影响,不会阻止事件的传播。如果要阻止传播,可以使用stopPropagation()stopImmediatePropagation()方法。

使用如下HTML

4043748824d482dba351964462471430.png

a053d9f20b0c1c84ca859b27fb4bf357.png

上面代码中,浏览器的默认行为是单击会选中单选框,取消这个行为,就导致无法选中单选框。

利用这个方法,可以为文本输入框设置校验条件。如果用户的输入不符合条件,就无法将字符输入文本框。

使用如下HTML

8b06b066cdbb13b58a174c97b2cb06e9.png

0f2b8a0637b079fa25918e42a25a2635.png

上面代码为文本框的keypress事件设定监听函数后,将只能输入小写字母,否则输入事件的默认行为(写入文本框)将被取消,导致不能向文本框输入内容。

3.2 Event.stopPropagation()

stopPropagation方法阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上其他的事件监听函数。

function stopEvent(e) {
  e.stopPropagation();
}

el.addEventListener('click', stopEvent, false);

上面代码中,click事件将不会进一步冒泡到el节点的父节点。

3.3 Event.stopImmediatePropagation()

Event.stopImmediatePropagation方法阻止同一个事件的其他监听函数被调用,不管监听函数定义在当前节点还是其他节点。也就是说,该方法阻止事件的传播,比Event.stopPropagation()更彻底。

如果同一个节点对于同一个事件指定了多个监听函数,这些函数会根据添加的顺序依次调用。只要其中有一个监听函数调用了Event.stopImmediatePropagation方法,其他的监听函数就不会再执行了:

f1c090e75d5f1a48841d20d9b618da36.png

上面代码在div节点上,为click事件添加了两个监听函数l1l2。由于l1调用了event.stopImmediatePropagation方法,所以l2不会被调用。

3.4 Event.composedPath()

Event.composedPath()返回一个数组,成员是事件的最底层节点和依次冒泡经过的所有上层节点(刷新页面后再输入新的代码):

c94561f20dc5568e1f4b8738eed52b52.png

上面代码中,click事件的最底层节点是p,向上依次是divbodyhtmldocumentWindow

由此我们就能看出冒泡的顺序了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值