JavaScript学习笔记——事件

要点

  • 大多数JavaScript代码都是用来响应事件的。
  • 要响应事件,可以编写一个事件处理程序赋给某个元素的属性(例如,可将处理程序赋给元素的onclick属性)
  • 事件处理程序(后文也称“处理程序”)是一个函数,在事件发生时执行
  • 短时间内发生大量事件,浏览器将时间按发生的顺序存储到事件队列中,依次调用其处理程序(应保证事件处理程序简洁高效,否则将导致队列中其他事件无法得到及时处理)
  • 处理事件的代码不同于从头到尾执行的代码:事件处理程序的运行时间和运行顺序都是不确定的,它们是异步的。

  • (1)DOM事件(发生在DOM元素上的事件)导致一个event对象被传递给处理程序
    event对象包含一些属性,这些属性提供了有关事件的细节信息,如事件的类型type("click""load")和目标target(触发事件的对象)
  • (2)对于基于时间的事件(如setTimeout()),关联处理程序与事件的方法 不是将处理程序赋给属性,而是将处理程序传递给某个函数,且不产生event对象

  • 方法getElementByTagName返回一个NodeList,其中包含0个、1个或更多的element对象,NodeList类似于数组,你可以对其进行迭代。

为何需要事件

  • 从前的编程方式通常都从上到下的、按顺序的、按部就班地执行的,这是线性(linear)的编码方式
  • 然而,JavaScript代码通常不是这样编写的,大多数JavaScript代码都是事件响应式的,这是异步(asynchronous)的编码方式(事件处理程序的运行时间和运行顺序都是不确定的)
  • 接下来,反思我们的编码方式,学习编写响应事件的代码及为何要这样做

由于JavaScript用于交互式的网页环境,在网页中随时都会有不可预测事件发生(如网页加载完毕、用户点击了按钮、定时器到期):这种不可预测性意味着我们不可能提前预知接下来发生什么,进而决定了JavaScript不可能按照既定的顺序执行代码而是被动响应事件

事件处理程序(也称回调函数/监听器)

我们希望每当有事件发生时处理事件,这需要事件处理程序

事件处理程序就是一个函数,当事件发生时,其事件处理程序将被调用,因此,事件处理程序也称为回调函数监听器

一个例子:如何创建事件处理程序

目标:网页上有一幅模糊的图像(一个<img>元素),点击图像后,替换为清晰的图像
其中,模糊的图像为"pictureblur.jpg",清晰的图像为"picture.jpg"

<body>
	<img id="picture1" src="picture1blur.jpg">
</body>

其中有两个事件处理程序:

  1. 网页完全加载后的事件处理程序init()(赋给window.onload属性)。
    ps.别忘了这里要使用网页的DOM(要修改HTML的<img>元素),因此要等网页(以及DOM)加载好后再运行我们的代码
  2. 图片被点击后的事件处理程序showAnswer()(赋给elem.onclick属性)
	window.onload = init;//网页加载完成后的事件处理程序init
	function init() {
		var image = document.getElementById("picture1");
		image.onclick = showAnswer;//点击图片时的事件处理程序showAnswer
	};
	
	function showAnswer() {
		var image = document.getElementById("picture1");
	image.src = "picture1.jpg";
	}

ps. 这里为什么要在showAnswer()再次调用一遍document.getElementById("picture")

别忘了作用域规则:在函数内部创建的变量都是局部变量,因此在showAnswer()中必须重新获取<img>元素


ps.这里在一个事件处理程序中(init)创建了其他事件处理程序(showAnswer),这体现了开头所说的异步编程风格,这种做法在JavaScript很常见

事件(Event)的工作原理

  • 浏览器将捕捉事件,对其进行分析,并检查是否有事件处理程序等待该事件发生
  • 若短时间内发生过多事件,浏览器维护一个事件队列
  • 浏览器只能逐个按顺序处理队列中的事件,因为只有一个队列和一个控制线程(因此,应该尽可能使事件处理程序简短而高效,否则会导致页面响应缓慢)

常用的事件

关于窗口的事件:
window.onload指定处理程序,网页加载完毕时触发
window.unload指定处理程序,用户关闭窗口/切换到其他网页时触发
window.resize指定处理程序,用户调整窗口大小时触发

关于元素对象的事件:
Elem.onclick:单击元素时触发
Elem.onkeypress:按下任何键时触发
Elem.onplay:单击<video>元素的播放按钮时触发
Elem.onpause:单击<video>元素的暂停按钮时触发

鼠标移动事件:
Elem.onmousemove在元素上移动鼠标时触发
Elem.onmouseover:鼠标位于元素上方时触发
Elem.onmouseout:鼠标从元素上方移开时触发
Elem.ondragstart:用户开始拖动元素/选择的文本时触发
Elem.ondrop:用户放下拖动的元素时触发

触屏设备上的事件:
Elem.touchstart:用户触摸并按住元素时触发
Elem.touched:用户停止触摸时触发

Elem.addEventListener()方法可以向一个元素添加多个相同类型的事件处理程序,而不覆盖现有的事件处理程序

例如

object.touchstart = function(){myScript};

等效于

object.addEventListener("touchstart", myScript);

事件对象:获取事件有关细节(如触发本事件的对象)

问:会传递参数给事件处理程序吗?
答:会给处理程序传递参数,这个参数就是事件对象


有些事件(如DOM事件)会生成事件对象,其中包含事件的有关细节(单击事件包含有关单击位置的信息,按键事件包含有关按下的是哪个键的信息,等等)
一些基于时间的时间则不生成事件对象,详见后文

  • 每当调用单击事件处理程序时:
  • 都将导致一个event对象(事件对象)被创建
  • 事件对象会被传递给事件处理程序,由事件对象可获取有关事件的细节

在事件处理程序中声明形参,事件对象会被传递给这个形参

	image.onclick = showAnswer;//点击图片时的事件处理程序showAnswer
	function showAnswer(eventObj) {
		var image = eventObj.target;
		image.src = image.id+".jpg";//image.id为"picture1"
	}

事件对象的常用属性

  • eventObj.target存储着触发事件的对象。通常是元素对象,也可为其他对象。
    如:点击某<image>元素触发了事件,则eventObj.target指向该<image>元素
  • eventObj.type指出事件的类型,是一个字符串,如"click""load"
  • eventObj.keyCode确定用户刚按下了哪个键。
  • eventObj.clientX确定用户单击的位置到浏览器窗口的左边缘的距离
  • eventObj.clientY确定用户单击的位置到浏览器窗口的上边缘的距离
  • eventObj.timeStamp事件的发生时间(较旧的IE版本不支持)
  • eventObj.touches一在触摸设备上,可使用我来确定用户使用了多少根手指来触摸屏幕。
Eg.鼠标移动事件(mousemove event)——实时显示坐标的程序
  • 鼠标在元素上移动时触发此事件,使用元素的属性onmousemove指定处理程序;
  • 此事件会生成并传递一个事件对象
    event对象其中包含如下属性:
    clientXclientY:鼠标相对于浏览器窗口左边缘和上边缘的距离,单位为像素。
    screenXscreenY:鼠标相对于设备屏幕左边缘和上边缘的距离,单位为像素。
    pagexpageY:鼠标相对于网页左边缘和上边缘的距离,单位为像素。

例如:在图像上移动鼠标时,显示坐标

	window.onload = init;
	function init() {
		var picture = document.getElementById("picture");
		picture.onmousemove = showCoords;//鼠标移动事件的处理程序
	}
	
	function showCoords(eventObj) {//传入事件对象
		var coords = document.getElementById("coords");//显示坐标的文本元素<p>
		var x = eventObj.pageX;
		var y = eventObj.pageY;
		coords.innerHTML = "picture coordinates: " + x + ", " + y;
	}

如何将处理程序与事件关联:两种情况

  1. 对于前面介绍的事件,将处理程序与事件关联的方法,总是将处理程序(回调函数)赋给某个属性,如onloadonclickonmousemove

但这种做法不适用于另一类事件:如基于时间的事件

  1. 对于基于时间的事件,将处理程序与事件关联的方法有很大不同:不是将处理程序赋给属性,而是将处理程序传递给某个函数,如setTimeout()setInterval()(调用函数时开始计时,到达设定的时间后触发时间处理程序)
    并且,基于时间的事件不会生成事件对象

问:setTimeout为何不向事件处理程序传递一个事件对象?`
答:事件对象主要用于DOM事件处理程序;
setTimeout不向处理程序传递事件对象,因为时间事件并非由特定的元素触发。

基于时间的事件

setTimeout()定时器

setTimeout(事件处理程序的函数名,计时时间,额外参数(触发事件时,被传递给处理程序))

  • 额外参数可选:0个,1个或更多(IE8及更早浏览器不支持额外参数)
  • 调用setTimeout(),将创建一个定时器,浏览器管理所有的定时器(可以同时有多个定时器)
  • 在倒计时结束后,将调用处理程序
  • 这里,将处理程序与事件关联的方法与之前不同:setTimeout传递了一个指向处理程序函数的引用(不是将处理程序赋给某个属性,而是调用函数setTimeout并向它传递处理程序)
  • 这里将函数传递给另一个函数:准确的说是将指向事件处理程序(函数)的引用传递给了setTimeout(另一个函数)
  • 在C或Java等语言中,像这样将一个函数传递给另一个函数根本行不通
    但在JavaScript中,这行得通。能够传递函数提供了一种强大的功能,在JavaScript中传递函数的情形非常普遍

setInterval()定时器:每隔一段时间触发一次

setTimeout(事件处理程序的函数名,间隔时间,额外参数(触发事件时,被传递给处理程序))

  • 每隔一段时间触发一次,调用事件处理程序
  • 要停止setIntervalsetInterval返回一个timer对象,将其传递给另一个函数clearInterval以停止该定时器

setTimeout实际上是一个方法,严格地说,它应写作window.setTimeout,但由于window是全局对象,可省略对象名,直接写作setTimeout,实际编写代码时经常这样做;
理论上,属性window.onload时也可以省略window,但大多数人都不会这样做,因为onload是一个常见的属性名(其他元素也可能有属性onload)。如果省略window,将让人不知道指的是哪个对象的onload属性。

通过给onload赋值,我们将一个处理程序关联到了相应的事件。但通过使用setTimeout,可以创建任意数量的定时器,并分别为每个定时器指定与之相关联的处理程序。

其他事件

除了有基于DOM的事件、定时器事件,还有很多不同类型的事件

  • 在JavaScript中,大部分事件都是DOM事件(如单击元素触发的事件)
    或定时器事件(使用setTimeoutsetInterval创建的事件)
  • 此外,还有与API相关的事件,如GeolocationLocalStorageWeb Worker等JavaScript API触发的事件
  • 最后,还有一系列与I/O相关的事件,如使用XmlHttpRequest向Web服务请求数据时引发的事件,以及使用Web套接字引发的事件
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值