【学习笔记】JS之事件(上)

前言

本篇文章是我的读书笔记,这里我直接从事件开始的原因是我之前没有写博客,最近一段时间才开始。之前的JS笔记也都有写,如果有人想看,欢迎留言/私信,我会把之前的整理出来。


JS 与 HTML 的交互是通过事件实现的

事件流

事件流就是描述接收事件的顺序。

IE支持事件的冒泡流,Netscape Communicator支持事件的捕获流。

别以为IE要停了就可以不学冒泡流了,DOM事件流是两者的结合哦!

1.事件冒泡

事件会从开始触发的元素逐层向上传播,现代的浏览器中的事件会一直冒泡到window对象

在这里插入图片描述

2.事件捕获

事件会从最不具体的节点元素传播到最具体的节点元素,所有浏览器都是从window对象开始捕获的,而DOM2Events规定是从document开始的。通常建议使用事件冒泡

在这里插入图片描述

3.DOM事件流

分为三个阶段:事件捕获、到达目标和事件冒泡。

事件捕获最先发生,为提前拦截事件提供可能。然后,实际的目标元素接收到事件。最后一个阶段是冒泡,最迟要在这个阶段响应事件。

在这里插入图片描述

实际的目标在捕获阶段不会接收到事件,因为在捕获阶段从document到<html>再到<body>就结束了。下一阶段再<div>元素上发生触发事件 “到达目标" 阶段,通常事件处理时被认为是冒泡阶段的一部分。

现代浏览器都会在捕获阶段在事件目标上触发事件,所以会有两个机会处理事件。

事件处理程序

事件意味着用户或浏览器执行的某种动作。为响应事件而调用的函数被称为事件处理程序,通常函数名以"on"开头

1.HTML事件处理程序

提前说明:这种方法使用的不多

特定元素支持的每个事件都可以使用事件处理程序的名字以HTML属性的形式来指定。因为属性的值是JS代码,所以要注意转义问题。

//具体格式如下
<input type="button" value="Click Me" onclick="console.log('Clicked')"/>

在该事件处理程序中可以调用在页面其他地方定义的脚本,可以访问全局作用域的一切。

以这种方式指定的事件处理程序,会创建一个函数来封装属性的值,函数有如下性质:

  • 这个函数有一个特殊的局部变量event,其保存的是event对象。函数的this值相当于事件的目标元素。

  • 其作用域链被扩展了。document和元素自身的成员都可以被当成局部变量访问,这是通过this实现的

    function() {
    	with(document) {
    		with(this) {
    			//属性值
    		}
    	}
    }
    //所以事件处理程序可以直接通过属性名访问自己的属性值。
    

但这种指定事件处理程序有一些问题:

  1. 时机问题。事件处理程序可能会在元素和用户已经交互后才会运行到,即事件处理程序写在了元素的后面。这时就会报错,所以用此方法注意js代码的位置,可以用try/catch封装
  2. 事件处理程序的作用域链的扩展在不同的浏览器中会有不同的结果。因为不同的js引擎中标识符解析规则存在差异。
  3. HTMLJS有强耦合,修改代码比较麻烦

2.DOM0事件处理程序

这种方法使用的更多

这种方法是传统方法,即把一个函数赋值给一个事件处理程序属性,要使用js指定事件处理程序,必须先取得要操作对象的引用

let btn = document.getElementById("myBtn");

然后把这个属性赋值为一个函数即可

//每个元素都有通常小写的事件处理程序属性
btn.onclick = function() {
	console.log("Clicked");
};

注:上面的代码在运行之后才会给事件处理程序赋值,如果在页面中上面的代码出现在按钮之后,可能出现没有反应的情况

事件处理程序会在元素的作用域中运行,即this等于元素。可以使用this引用元素本身和访问元素的任何属性和方法

以这种方式添加事件处理程序是注册在事件流的冒泡阶段。通过将事件处理程序属性的值设置为null,可以移除通过DOM0方式添加的事件处理程序

3.DOM2事件处理程序

DOM2Events为事件处理程序的赋值和移除定义了两个方法:addEventListener()removeEventListener()

这两个方法的参数一致:事件名、事件处理函数和一个布尔值。true表示在捕获阶段调用事件处理程序,false(默认)表示在冒泡阶段调用。所有DOM节点都有这两种方法。

//用法
let btn = document.getElementById("myBtn");
let handler = function() {
    console.log(this.id);
}
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false);

使用此方式的优势可以为一个事件添加多个事件处理程序,DOM0只能添加一个。

注:使用这两种方法时不建议添加匿名函数,因为移除事件处理程序时必须保证和添加时的参数值是一样的,匿名函数没有名字所以无法保证相同,就无法移除。

大多情况都会选择将事件处理程序添加到事件流的冒泡阶段,主要原因是跨浏览器兼容性好。放到捕获阶段通常用于拦截事件。

4.跨浏览器事件处理程序

由于IE不久就会停用,所以可以不考虑兼容IE

代码如下:

var EventUtil = {
	addHandler: function(element, type, handler) {
		if (element.addEventListener)
			element.addEventListener(type, handler,false);
		else
			element["on" + type] = handler;
	}
	removeHandler: function(element, type, handler) {
		if (element.addEventListener)
			element.removeEventListener(type, handler,false);
		else
			element["on" + type] = null;
	}
};

事件对象

DOM中发生事件时,所有相关信息都会被收集并存储在一个名为event的对象中。同样不看IE,所以下面说的都是DOM事件对象。event对象在事件处理程序执行完毕后,就会被销毁。

DOM事件对象

event对象是传给事件处理程序的唯一参数,不管是DOM0还是DOM2都会传入这个对象。通过HTML属性指定的事件处理程序,同样可以使用。

不同事件生成的事件对象会包含不同的属性和方法,但也有一些公共的属性和方法。如下:

在这里插入图片描述

在这里插入图片描述

this、currentTarget 和 target的区别

在事件处理程序内,this对象始终等于currentTargettarget只包含事件的实际目标。如果事件处理程序直接添加到实际的目标(比如,将点击事件处理程序直接添加到一个按钮上)这时这三个值都一样的。

如果没有添加到按钮上,而是添加到其父级节点上,那么target就和其他两个不一样了。target属性等于按钮,但按钮没有注册事件处理程序,所以事件会冒泡到其父级节点上。thiscurrentTarget都等于父级节点。

type属性

type属性在处理程序处理多个事件时很有用,比如:

let btn = document.getElementById("mybtn");
let handler = function(event) {
	switch(event.type) {
		case "click":	//点击事件
			console.log("Clicked");
			break;
		case "mouseover":	//鼠标在其上方事件
			event.target.style.backgroundColor = "red";
			break;
		case "mouseout":	//鼠标移走事件
			event.target.style.backgroundColor = "";
			break;
	}
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;

preventDefault()方法

用于阻止特定事件的默认动作。任何可以使用此方法取消默认行为的事件,其事件对象cancelable属性都会设置为true

let link = document.getElementById("mylink");
link.onclick = function(event) {
	event.preventDefalult();
};

stopPropagation()方法

用于立即阻止事件流在DOM结构中传播,取消后续的事件捕获或冒泡。

let link = document.getElementById("mylink");
link.onclick = function(event) {
	console.log("Clicked");
	event.stopPropagation();
};
document.body.onclick = function(event) {
	console.log("body clicked");
};
//Clicked
//不会输出body clicked,因为取消了冒泡

eventPhase属性

用于确定事件流当前所处的阶段。

  • 捕获阶段:1
  • 目标上:2
  • 冒泡阶段:3

结语

事件的内容有点多,先讲到这里,后面是关于事件的类型、事件的委托和模拟事件,我们下次再说~~~


阅读的文章是《JavaScript高级程序设计(第四版)》

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>