JavaScript——7:事件及事件处理

JavaScript 与用户之间的文互是通过事件驱动来实现的。

一,事件概念

所谓的”JavaScript使我们能够实现Web页面的交互性“,很大程度上说的就是JavaScript允许Web页面对访问者做的某件事情做出响应。

事件是用户在访问页面时执行的操作。当浏览器探测到在某个事件目标上触发了某种事件类型中的某个事件时,它可以执行绑定到该事件的事件处理程序,从而实现灵活的交互性。

(一)事件处理模型

在浏览器的不同发展阶段与不同的平台中,存在几种不同的[事件处理模型:

  1. DOM Level 0:是浏览器初期出现的一种比较简单的事件模型,主要通过事件属性为指定标签绑定事件处理函数。早期的IE和Netscape就提供了功能相似的API来分摊服务器处理压力。
  2. DOM Level 2:由 W3C 制定的标准事件处理模型,所有的主要浏览器都支持这个标准。这种事件模型包括 DOM2 事件模块和 DOM3 事件模块,
  3. Specific model:主要用于IE4 - IE8 和Netscape4 - Netscape 6等不同浏览器及其不同阶段。

不同事件处理模型的简单说明可以参考这里

(二)事件流

当有在相同事件类型上注册事件处理程序的两个元素嵌套在一起时,如果用户单击内部元素的话,那么该如何进行处理呢?

早期的IE和Netscape就都想过这个问题,并就“多个节点对象对同一种事件进行响应的先后顺序”做出了不同的处理:IE派的事件流是事件冒泡流,Netscape Communicator派的事件流是事件捕获流。

1,事件冒泡流

事件开始时由最特定的元素接收, 然后逐级向外传播到较为不具体的目标触发,也就是事件从内向外进行响应。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>example</title>
	</head>
	<body>
		<div>click here!</div>
	</body>
</html>

点击后将按div -> body -> html -> document的顺序进行响应,具体到不同浏览器甚至不同版本会有差别。

2,事件捕获流

事件开始时由不最特定的元素接收, 然后逐级向内传播到最特定的目标触发,也就是事件从外向内进行响应。

点击后将按document -> html -> body -> div 的顺序进行响应。但是其他浏览器也逐渐在支持这种事件处理类型,只是具体来说会有细节差别。

3,W3C的做法

W3C作为国际标准组织,在IE与Netscape的大战中采用了折中的方案:首先发生的是事件捕获,为截获事件提供了机会,然后是实际的目标接收到事件,最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。

但实际上,多数浏览器都会在捕获阶段触发事件对象上的事件,结果就是有两个机会在目标对象上面操作事件。

(三)注册事件处理程序

注册事件处理程序有两种基本方式:

  1. 在Web初期, 给事件目标对象或文档元素设置属性。
  2. 更通用的方法,是将事件处理程序传递给对象或元素的一个方法。

1,HTML事件处理程序

把 JavaScript 脚本作为属性值,直接赋予给事件属性。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>example</title>
		<script>
			function myFunction(id) {
				let e = document.getElementById(id);
				return e.value;
			}
		</script>
	</head>
	<body>
		<form method='post'>
			<input type="text" id="ipt" name="username" value="">
			<input type="button" id="btn" name="btn" value="Echo Username" onclick="value=myFunction('ipt')"> //HTML事件属性值就是一段JavaScript代码
		</form>
	</body>
</html>
  • 按钮显示输入框输入的内容。

在HTML中定义的事件处理程序可以包含要执行的具体动作, 也可以调用在页面其他地方定义的脚本。

(1)优点

使用一个事件属性看起来确实很简单,早期的事件绑定也是这样实现的;

还有一个不太能算优点的有点,通过这种方式,能在JavaScript函数中使用with语句扩展作用域:

<html>
	<head>
		<script type="text/javascript">
			function validate_required(field, alerttxt) {
				with(field) {
					if (value === null || value === "") {
						alert(alerttxt);
						return false;
					} else {
						return true;
					}
				}
			}

			function validate_form(thisform) {
				with(thisform) {
					if (validate_required(email, "Email must be filled out!") == false) {
						email.focus();
						return false;
					}
				}
			}
		</script>
	</head>
	<body>
		<form action="" onsubmit="return validate_form(this)" method="post">
			Email: <input type="text" name="email" size="30">
			<input type="submit" value="Submit">
		</form>
	</body>
</html>
  • 简单校验表单内容。
(2)缺点

如果validate_form()函数在页面的最底部定义,且用户在页面解析函数之前就单击了按钮, 就会引发错误;

在HTML事件处理程序中用with语句会带来较大的性能损耗

但最突出的缺点是HTML与JavaScript代码的紧密耦合。如果要更换事件处理程序,就要改动HTML代码和JavaScript代码两个地方,这明显不符合非侵入式JavaScript设计理念

2,DOM Level 0事件处理程序

把事件处理函数作为属性值,赋予给 DOM 对象的事件属性,这是指定事件处理程序的传统方式,而且至今仍然为所有现代浏览器所支持。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Useful event target example</title>
		<style>
			div {
				background-color: red;
				height: 100px;
				width: 25%;
				float: left;
			}
		</style>
	</head>
	<body>
		<script>
			window.onload = initPage('div');

			function initPage(ename) {
				for (let i = 1; i <= 16; i++) {
					const myDiv = document.createElement(ename);
					document.body.appendChild(myDiv);
				}
				
				const divs = document.querySelectorAll(ename);
				
				for (let i = 0; i < divs.length; i++) {
					divs[i].onclick = function() {
						this.style.backgroundColor = bgChange();
					}
				}
			}
			
			function random(number) {
				return Math.floor(Math.random() * number);
			}
			
			function bgChange() {
				const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
				return rndCol;
			}
		</script>
	</body>
</html>
  • 变色墙。

这里在事件处理程序中通过this关键字访问元素的属性,以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。

(1)优点

简单且跨浏览器实现。指定事件处理程序的方法简单,销毁事件处理程序的方法也很简单:e.onclick=null;

相较于HTML事件处理程序,一定个程度上解耦了html内容层与js行为层;

(2)缺点

一个事件只能注册一个事件处理函数。如果为对象同一事件绑定多个事件处理函数,则后面的会覆盖前面的,只执行最后一个;

要使用DOM Level 0事件处理程序, 首先必须取得一个要操作的对象的引用,但是,在运行事件处理程序代码以前不会为对象指定事件, 因此如果这些代码在页面中位于要操作对象的后面, 就有可能因为还没被加载完成而没起作用。

3,DOM Level 2事件处理程序

DOM Level 2事件定义了两个方法:

所有DOM节点中都包含这两个方法, 并且它们都接受3个参数:

  1. 要处理的事件名
  2. 作为事件处理程序的函数
  3. 指定事件响应阶段的布尔值
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Useful event target example</title>
		<style>
			button {
				border: none;
				font-size: large;
				height: 60px;
				width: 200px;
				text-align: center;
			}
		</style>
	</head>
	<body>
		<button id="btn1">clicl me!</button>
		<script>
			window.onload = initPage;

			function initPage() {
				const btn = document.getElementById('btn1');
				btn.addEventListener("click", bgChange, false);
			}

			function random(number) {
				return Math.floor(Math.random() * number);
			}

			function bgChange() {
				const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
				this.style.backgroundColor = rndCol;
			}
		</script>
	</body>
</html>
  • 点击按钮变色。
  • addEventListener()为btn对象绑定事件:"click"指定事件类型名,bgChange为事件处理程序的函数,false指定在冒泡阶段进行事件响应。

使用 addEventListener() 方法能够为多个对象注册相同的事件处理函数,也可以为同一个对象注册多个事件处理函数,这对于模块化开发非常有用:

function initPage() {
	const btn = document.getElementById('btn1');
	btn.addEventListener("mouseover", bgChange, false);
	btn.addEventListener("mouseout", bgChange, false);
}
  • 鼠标移入移出变色。

通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除,移除时传入的参数与添加处理程序时使用的参数相同:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Useful event target example</title>
		<style>
			button {
				border: none;
				font-size: large;
				height: 60px;
				width: 200px;
				text-align: center;
			}
		</style>
	</head>
	<body>
		<button id="btn1">clicl me!</button>
		<button id="btn2">remove</button>
		<script>
			window.onload = initPage;

			function initPage() {
				const btn1 = document.getElementById('btn1');
				btn1.addEventListener("mouseover", bgChange, false);
				btn1.addEventListener("mouseout", bgChange, false);
				const btn2 = document.getElementById('btn2');
				btn2.addEventListener("click", rmChange, false);
			}

			function random(number) {
				return Math.floor(Math.random() * number);
			}

			function bgChange() {
				const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
				this.style.backgroundColor = rndCol;
			}
			
			function rmChange() {
				const btn1 = document.getElementById('btn1');
				btn1.removeEventListener("mouseover", bgChange, false);
			}
		</script>
	</body>
</html>
  • 点击按钮取消其移入变色。

大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段, 这样可以最大限度地兼容各种浏览器。 最好只在需要在事件到达目标之前截获它的时候将事件处理程序添加到捕获阶段。

(1)优点

可同时为对象同一事件绑定多个事件处理函数,然后顺序执行,不会覆盖;

(2)缺点

不具有跨浏览器优势,具体实现时要做兼容处理;

4,IE事件处理程序

限于篇幅,参考IE事件处理程序attachEvent detachEvent

5,跨浏览器的事件处理程序

只要恰当地进行客户端检测,使用能够隔离浏览器差异的JavaScript库,就能实现跨浏览器的事件处理程序。要保证处理事件的代码能在大多数浏览器下一致地运行,只需关注冒泡阶段。可以参考跨浏览器的事件处理程序实现总结跨浏览器事件处理程序

(四)使用 event 对象

在触发DOM上的某个事件时会产生一个事件对象event,event 对象的供了有关事件的细节。

1,DOM中的事件对象

兼容DOM的浏览器会将一个event对象传入到事件处理程序中,然后访问其属性提获得事件信息,使用其方法可以控制事件的传播:

<input type="button" value="Click Me" onelick="alert(event.type)"/>

const btn = document.querySelector('button');
btn.onclick = function (e) {
	console.log(e.currentTarget);
};
btn.addEventListener('click', function (e){
	console.log(e.type);
}, false);

在这里插入图片描述

2,IE中的事件对象

与访问DOM中的event对象不同,要访问IE中的event对象有几种不同的方式, 取决于选择的事件处理程序的方法。

如果使用DOM level 0方法添加事件处理程序时, event对象作为window对象的一个属性存在:

const btn = document.querySelector('button');
btn.onclick = function () {
	var e = window.event;
	console.log(e.currentTarget);
};

如果使用IE事件处理程序即使用attachEvent()注册事件处理程序时,有一个event对象作为参数被传入事件处理程序函数中,也可以通过window对象来访问event对象:

const btn = document.querySelector('button');
btn.addEvent('onclicl', function (e) {
	console.log(e.type);
});

DOM Level 2 Events 规范定义了 一个标准的事件模型,它被除了 IE 怪异模式以外的所有现代浏览器所实现,而 IE 定义了专用的、不兼容的模型。简单比较两种事件模型如下:

  • 在 DOM 事件模型中, event 对象被传递给事件处理函数,但是在 IE 事件模型中,它被存储在 window 对象的 event 属性中。
  • 在 DOM 事件模型中, Event 类型的各种子接口定义了额外的属性,它们提供了与特定事件类型相关的细节;在 IE 事件模型中只有一种类型的 event 对象,它用于所有类型的事件。

3,跨浏览器的事件对象

虽然DOM和IE中的event对象不同, 但基于它们之间的相似性依旧可以拿出跨浏览器的方案来,比如JavaScript跨浏览器处理事件以及相关对象

更详细的跨浏览器事件兼容性请参考W3C DOM Compatibility - EventsEvent compatibility tables

由于在具体应用中存在的不兼容情况,导致事件的相关概念与实现具体而繁杂,所以上面只是进行了简单的介绍。
接下来就不同的事件类型进行简单介绍。

二,处理页面事件

(一)页面初始化

load 事件类型在页面完全加载完毕的时候触发。

window.onload = initPage;
function initPage() {
	alert('window.onload = initPage;');
}

在实际开发中,常常会使用load 事件类型进行页面初始化:

window.onload = initPage;
function initPage() {
	var obj = document.querySelector('button');
	if (window.addEventListener) {
		f1(obj);
	}else{
		f2(obj);
	}
	f3("The initialization task is completed!");
}
function f1(obj) {
	obj.addEventListener('click', doEvent, false);
}
			
function f2(obj) {
	obj.attachEvent('onclick', doEvent);
}
function f3(prm) {
	alert(prm);
}
			
function doEvent() {
	if (confirm("Are you sure you want to do that?")) {
			alert("You said yes");
	} else {
			alert("You said no");
	}
}

(二)结构初始化

由于 load 事件需要等到所有图形图像、 css和JS文件等静态文件)全部载入完成之后才会被触发,如果不需要等待庞大静态文件加载完,只希望某些脚本能够在所有DOM节点加载完毕之后就能够被执行,可使用 DOMContentLoaded 事件类型:

window.onload = initPage;

document.addEventListener("DOMContentLoaded", function() {
	alert("The task of loading DOM is completed ahead of time!")}, false);

function initPage() {
	alert("The initialization task is completed!");
}
  • IE 事件模型不支持 DOMContentLoaded 事件类型。

(三)页面卸载

只要用户从一个页面切换到另一个页面就会触发unload事件

window.onunload = function () {
	alert("感谢你访问本页面,再见!");
};

window.onbeforeunload事件比unload事件更加人性化:

<!DOCTYPE html>
<html>
	<head>
		<title>FabulousAirTickets.com</title>
		<script src="script02.js"></script>
	</head>
	<body>
		<h2>FabulousAirTickets.com</h2>
		<form action="#">
			<p>
				<label for="from">From:</label>
				<input type="text" id="from">
				&nbsp;&nbsp;
				<label for="to">To:</label>
				<input type="text" id="to">
			</p>
			<p>
				<label for="leavedate">DepartureDate:</label>
				<input type="date" id="leavedate">
				&nbsp;&nbsp;
				<label for="returndate">ReturnDate:</label>
				<input type="date" id="returndate">
			</p>
			<p>
				# of Adults:
				<select>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
					<option value="4">4</option>
				</select>
			</p>
			<p>
				<input type="submit" value="Find Flights!">
				&nbsp;&nbsp;
				<input type="reset">
			</p>
		</form>
		<script>
			window.onbeforeunload = function() {
				return "If you close this window, your flight choices will be lost!";
			}
		</script>
	</body>
</html>
  • 离开页面前提醒保存表单数据。

(四)窗口重置

文档视图调整大小时会触发 resize 事件

<body>
	<div id="box"></div>
	<script>
		var box = document.getElementById("box"); // 获取盒子的引用指针
		box.style.position = "absolute"; // 绝对定位
		box.style.backgroundColor = "red"; // 背景色
		box.style.width = w() * 0.8 + "px"; // 设置盒子宽度为窗口宽度的0.8倍
		box.style.height = h() * 0.8 + "px"; // 设置盒子高度为窗口高度的0.8倍
		window.onresize = function() { // 注册resize事件处理函数,动态调整盒子大小
			box.style.width = w() * 0.8 + "px";
			box.style.height = h() * 0.8 + "px";
		}
		function w() { // 获取窗口宽度
			if (window.innerWidth) // 兼容DOM
				return window.innerWidth;
			else if ((document.body) && (document.body.clientWidth))
				// 兼容IE
				return document.body.clientWidth;
		}
		function h() { // 获取窗口高度
			if (window.innerHeight) // 兼容DOM
				return window.innerHeight;
			else if ((document.body) && (document.body.clientHeight))
				// 兼容IE
				return document.body.clientHeight;
		}
	</script>
</body>
  • 据窗口调整内容大小。

(五)页面滚动

文档视图或者一个元素在滚动时,会触发元素的scroll事件。利用该事件可以跟踪文档位置变化,及时调整某些元素的显示位置,确保它始终显示在屏幕可见区域中。

<body>
	<div id="box"></div>
	<script>
		var box = document.getElementById("box");
		box.style.position = "absolute";
		box.style.backgroundColor = "red";
		box.style.width = "200px";
		box.style.height = "160px";
		window.onload = f; // 页面初始化时固定其位置
		window.onscroll = f; // 当文档位置发生变化时重新固定其位置
		function f() { // 元素位置固定函数
			box.style.left = 100 + parseInt(document.body.scrollLeft) + "px";
			box.style.top = 100 + parseInt(document.body.scrollTop) + "px";
		}
	</script>
	<div style="height:2000px;width:2000px;"></div>
</body>
  • 页面滚动,但内容始终相对位置不变。

(六)错误处理

error 事件类型是在 JavaScript 代码发生错误时触发的,利用该事件可以捕获并处理错误信息。

三,处理鼠标事件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
	</head>
	<body>
		<div align="center">
			<h1>在按钮上试试</h1>
			<input type="text" style="font-size:larger;" />
			<br />
			<button style="margin: 10px; font-size:larger;">来这里来玩玩儿</button>
		</div>
		<script>
			var btn = document.getElementsByTagName("button")[0]; 
			var t = document.getElementsByTagName("input")[0]; 
			function f() { //事件处理函数
				var event = event || window.event; //标准化事件对象
				t.value = (event.type); //获取当前事件类型
			}
			btn.onmouseover = f; //注册鼠标经过时事件处理函数
			btn.onmouseout = f; //注册鼠标移开时事件处理函数
			btn.onmousedown = f; //注册鼠标按下时事件处理函数
			btn.onmouseup = f; //注册鼠标松开时事件处理函数
			btn.onmousemove = f; //注册鼠标移动时事件处理函数
			btn.onclick = f; //注册鼠标单击时事件处理函数
			btn.ondblclick = f; //注册鼠标双击时事件处理函数
		</script>
	</body>
</html>

(一)鼠标点击

鼠标点击事件包括4种类型 click 单击dblclick 双击mousedown 按下mouseup 松开

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<style>
			div {
				border-width: 100px;
			}

			body {
				background - color: #5500ff;
			}

			img {
				margin: 0 10 px;
				border: 3 px #00F solid;
				width: 60px;
				height: 60px;
			}

			button {
				height: 30px;
				width: 60px;
			}
		</style>
		<script>
			window.onload = initPage;

			function initPage() {
				for (var i = 0; i < document.links.length; i++) {
					document.links[i].onclick = initLinkClick;
				}

				for (var i = 0; i < document.images.length; i++) {
					document.images[i].ondblclick = newWindow;
				}

				var btn = document.getElementsByTagName("button")[0];
				btn.addEventListener("mousedown", bgChange, false);
				btn.addEventListener("mouseup", bgChange, false);
			}

			function newWindow() {
				var src = this.src;
				src = src.substring(src.lastIndexOf("/") + 1);
				alert(src);
				var imgName = src;
				window.open(imgName, "imgWin", "width=320,height=240,scrollbars=no");
			}

			function initLinkClick(TagName) {
				if ((new RegExp(window.location.href)).test(this.href)) {
					// 如果当前超链接href属性中包含本页面的URL信息
					alert("self链接为#,这里单击鼠标时不会刷新本页面!");
					return false; // 将禁止超链接的默认行为
				}
			}

			function random(number) {
				return Math.floor(Math.random() * number);
			}

			function bgChange() {
				const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
				this.style.backgroundColor = rndCol;
			}
		</script>
	</head>
	<body>
		<div>
			<ul>
				<li>
					<a name="tag" id="link1" href="#">self</a>
				</li>
				<li>
					<a name="tag" id="link2" href="https://developer.mozilla.org/zh-CN/">MDN</a>
				</li>
				<li>
					<a name="tag" id="link3" href="https://golang.google.cn/doc/tutorial/getting-started">Go</a>
				</li>
				<li>
					<a name="tag" id="link4" href="https://en.wikipedia.org/wiki/Main_Page">Wikipedia</a>
				</li>
			</ul>
		</div>
		<div>
			<h3>双击图片放大</h3>
			<img src="crabnebula.jpg" alt="crabnebula" id="Img0">
			<img src="europa.jpg" alt="europa" id="Img1">
		</div>
		<div>
			<button>点击</button>
		</div>
	</body>
</html>
  • 新标签打开大图片。
<!DOCTYPE html>
<html>
	<head>
		<title>Image Popup</title>
		<link rel="stylesheet" href="script05.css">
		<style type="text/css">
			#adpicture {
				position: fixed;
				z-index: 99;
				top: 20%;
				right: 50%;
			}

			#close {
				position: absolute;
				left: 10px;
				top: 5px;
			}
		</style>
		<script type="text/javascript">
			window.onload = iniPage;
			
			function iniPage() {
				adPicture();
			}
			
			function adPicture() {
				var mask = document.getElementById('close');
				var img = document.getElementsByTagName('img')[0];
				mask.onclick = function() {
					img.style.display = "none";
					this.style.display = "none";
				}
			}
		</script>
	</head>
	<body>
		<div id="adpicture">
			<button id="close" style="margin-left:50%;">关闭</button>
			<a href="https://blog.csdn.net/dangfulin/article/list/?ops_request_misc=&request_id=&biz_id=102&utm_term=dangfulin&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-list.nonecase">
				<img src="images/Img0_thumb.jpg" alt="广告位" style="width:400px;height:300px; margin-left:50%;">
			</a>
		</div>
	</body>
</html>
  • 顶部广告图片。
在这里插入代码片

(二)鼠标移动

当鼠标指针的位置发生变化时会触发 mousemove 事件

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
	</head>
	<body>
		<div id="box"></div>
		<script>
			// 初始化拖放对象
			var box = document.getElementById("box");
			// 获取页面中被拖放元素的引用指针
			box.style.position = "absolute"; // 绝对定位
			box.style.width = "160px"; // 定义宽度
			box.style.height = "120px"; // 定义高度
			box.style.backgroundColor = "red"; // 定义背景色
			// 初始化变量,标准化事件对象
			var mx, my, ox, oy; // 定义备用变量
			function e(event) { // 定义事件对象标准化函数
				if (!event) { // 兼容IE浏览器
					event = window.event;
					event.target = event.srcElement;
					event.layerX = event.offsetX;
					event.layerY = event.offsetY;
				}
				event.mx = event.pageX || event.clientX + document.body.scrollLeft;
				// 计算鼠标指针的x轴距离
				event.my = event.pageY || event.clientY + document.body.scrollTop;
				// 计算鼠标指针的y轴距离
				return event; // 返回标准化的事件对象
			}
			// 定义鼠标事件处理函数
			document.onmousedown = function(event) { // 按下鼠标时,初始化处理
				event = e(event); // 获取标准事件对象
				o = event.target; // 获取当前拖放的元素
				ox = parseInt(o.offsetLeft); // 拖放元素的x轴坐标
				oy = parseInt(o.offsetTop); // 拖放元素的y轴坐标
				mx = event.mx; // 按下鼠标指针的x轴坐标
				my = event.my; // 按下鼠标指针的y轴坐标
				document.onmousemove = move; // 注册鼠标移动事件处理函数
				document.onmouseup = stop; // 注册松开鼠标事件处理函数
			}

			function move(event) { // 鼠标移动处理函数
				event = e(event);
				o.style.left = ox + event.mx - mx + "px"; // 定义拖动元素的x轴距离
				o.style.top = oy + event.my - my + "px"; // 定义拖动元素的y轴距离
			}

			function stop(event) { // 松开鼠标处理函数
				event = e(event);
				ox = parseInt(o.offsetLeft); // 记录拖放元素的x轴坐标
				oy = parseInt(o.offsetTop); // 记录拖放元素的y轴坐标
				mx = event.mx; // 记录鼠标指针的x轴坐标
				my = event.my; // 记录鼠标指针的y轴坐标
				o = document.onmousemove = document.onmouseup = null;
				// 释放所有操作对象
			}
		</script>
	</body>
</html>
  • 鼠标点击不放,内容跟随移动。
<!DOCTYPE html>
<html>
	<head>
		<title>Mouse Movements</title>
		<style>
			body {
				background-color: #FFF;
			}

			#lEye,
			#rEye {
				position: absolute;
				top: 100px;
				width: 24px;
				height: 25px;
			}

			#lDot,
			#rDot {
				position: absolute;
				top: 113px;
				width: 4px;
				height: 4px;
			}

			#lEye {
				left: 100px;
			}

			#rEye {
				left: 150px;
			}

			#lDot {
				left: 118px;
			}

			#rDot {
				left: 153px;
			}
		</style>
	</head>
	<body>
		<img src="images/circle.gif" alt="left eye" id="lEye">
		<img src="images/circle.gif" alt="right eye" id="rEye">
		<img src="images/lilRed.gif" alt="left eyeball" id="lDot">
		<img src="images/lilRed.gif" alt="right eyeball" id="rDot">
	</body>
	<script>
		document.onmousemove = moveHandler;

		function moveHandler(evt) {
			if (!evt) {
				evt = window.event;
			}
			animateEyes(evt.clientX, evt.clientY);
		}

		function animateEyes(xPos, yPos) {
			var rightEye = document.getElementById("rEye");
			var leftEye = document.getElementById("lEye");
			var rightEyeball = document.getElementById("rDot").style;
			var leftEyeball = document.getElementById("lDot").style;

			leftEyeball.left = newEyeballPos(xPos, leftEye.offsetLeft);
			leftEyeball.top = newEyeballPos(yPos, leftEye.offsetTop);
			rightEyeball.left = newEyeballPos(xPos, rightEye.offsetLeft);
			rightEyeball.top = newEyeballPos(yPos, rightEye.offsetTop);

			function newEyeballPos(currPos, eyePos) {
				return Math.min(Math.max(currPos, eyePos + 3), eyePos + 17) + "px";
			}
		}
	</script>
</html>
  • 眼睛跟随鼠标移动。用到以下图片:
    circle
    lilRed

(三)鼠标经过

当移动鼠标指针到某个元素上时,将触发 mouseover 事件,而当把鼠标指针移出某个元素时,将触发 mouseout 事件

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
	</head>
	<style >
		div {
			border-width:100px;
		}
	</style >
	<body>
		<div id="lv1">
			<div id="lv2">
				<div id="lv3">盒子</div>
			</div>
		</div>
		<script>
			var div = document.getElementsByTagName("div");
			// 获取3个嵌套的div元素
			for (var i = 0; i < div.length; i++) { // 遍历嵌套的div元素
				div[i].onmouseover = function(e) { // 注册移过事件处理函数
					this.style.border = "solid blue";
				}
				div[i].onmouseout = function(e) { // 注册移出事件处理函数
					e.target.style.border = "solid red";
					console.log(e.target.id);
				}
			}
		</script>
	</body>
</html>
  • 鼠标经过,边框变色。

(四)鼠标定位

当事件发生时,获取鼠标的位置是很重要的事情。以下属性都以像素值定义了鼠标指针的坐标:
在这里插入图片描述
从表中看得出来,以上属性参照的坐标系不同,导致准确计算鼠标的位置比较麻烦。

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
	</head>
	<body>
		<p id="move">鼠标跟随</p>
		<script>
			var div1 = document.getElementById("move");
			document.onmousemove = function(event) {
				pos(div1, 10, 10, event);
			}
			var pos = function(o, x, y, event) { // 鼠标定位赋值函数
				var posX = 0, posY = 0; // 临时变量值
				var e = event || window.event; // 标准化事件对象
				if (e.pageX || e.pageY) { // 获取鼠标指针的当前坐标值
					posX = e.pageX;
					posY = e.pageY;
				} else if (e.clientX || e.clientY) {
					posX = e.clientX + document.documentElement.scrollLeft +
						document.body.scrollLeft;
					posY = e.clientY + document.documentElement.scrollTop +
						document.body.scrollTop;
				}
				o.style.position = "absolute"; // 定义当前对象为绝对定位
				o.style.top = (posY + y) + "px";
				// 用鼠标指针的y轴坐标和传入偏移值设置对象y轴坐标
				o.style.left = (posX + x) + "px";
				// 用鼠标指针的x轴坐标和传入偏移值设置对象x轴坐标
			}
		</script>
	</body>
</html>
  • 鼠标跟随。
<!DOCTYPE html>
<html>
	<head>
		<title>Mouse Movements</title>
		<link rel="stylesheet" href="test.css">
		<script src="test.js"></script>
	</head>
	<body>
		<img src="images/circle.gif" alt="left eye" id="lEye">
		<img src="images/circle.gif" alt="right eye" id="rEye">
		<img src="images/lilRed.gif" alt="left eyeball" id="lDot">
		<img src="images/lilRed.gif" alt="right eyeball" id="rDot">
	</body>
</html>
body {
	background-color: #FFF;
}

#lEye, #rEye {
	position: absolute;
	top: 100px;
	width: 24px;
	height: 25px;
}

#lDot, #rDot {
	position: absolute;
	top: 113px;
	width: 4px;
	height: 4px;
}

#lEye {
	left: 100px;
}

#rEye {
	left: 150px;
}

#lDot {
	left: 118px;
}

#rDot {
	left: 153px;
}
document.onmousemove = moveHandler;

function moveHandler(evt) {
	if (!evt) {
		evt = window.event;
	}
	animateEyes(evt.clientX, evt.clientY);
}

function animateEyes(xPos,yPos) {
	var rightEye = document.getElementById("rEye");
	var leftEye = document.getElementById("lEye");
	var rightEyeball = document.getElementById("rDot").style;
	var leftEyeball = document.getElementById("lDot").style;

	leftEyeball.left = newEyeballPos(xPos, leftEye.offsetLeft);
	leftEyeball.top = newEyeballPos(yPos, leftEye.offsetTop);
	rightEyeball.left = newEyeballPos(xPos, rightEye.offsetLeft);
	rightEyeball.top = newEyeballPos(yPos, rightEye.offsetTop);

	function newEyeballPos(currPos,eyePos) {
		return Math.min(Math.max(currPos,eyePos+3), eyePos+17) + "px";
	}
}
  • 图片眼神跟随鼠标。

(五)鼠标按键

通过鼠标事件对象的 button 属性可以获取当前鼠标按下的键:

按键DOM 事件模型IE 事件模型
左键01
中键12
右键24
<body>
	<a href="https://developer.mozilla.org/zh-CN/">左键点击我跳转!</a>
	<br />
	<a href="https://developer.mozilla.org/zh-CN/">左键点击我跳转!</a>
	<br />
	<a href="https://developer.mozilla.org/zh-CN/">左键点击我跳转!</a>
	<br />
	<a href="https://developer.mozilla.org/zh-CN/">左键点击我跳转!</a>
	<script>
		var el = document.getElementsByTagName("a");
		for (var i = 0; i < el.length; i++) {
			el[i].onclick = function(e) {
				var e = e || window.event; // 标准化事件对象
				if (e.button == 0) {
					e.preventDefault(); // 禁止事件默认行为
					alert("对不起,该链接上左键点击失效!");
					return false;
				}
			};
		}
	</script>
</body>

但现在有些鼠标不仅仅只有三键,这可以用到MouseEvent.buttons属性进行判断情况,这个只读属性指示事件触发时哪个或哪些鼠标按键被按下:

按键DOM 事件模型
无按键0
左键1
右键2
滚轮或中键4
浏览器后退键8
浏览器前进键16

四,处理表单事件

表单事件处理主要用来验证表单。通过使用下面列出的事件,可以处理用户在表单上所做的任何操作。

(一)焦点处理

onfocus 事件在对象获得焦点时发生。onblur事件在对象失去焦点时发生。

<!DOCTYPE html>
<html>
	<head>
		<title>FabulousAirTickets.com</title>
		<script src="script02.js"></script>
		<style>
			input {
				height: 30px;
				width: 300px;
				font-size: large;
				background-color: #ff6063;
			}
		</style>
	</head>
	<body>
		<form id="form">
			<p id="error" hidden>Please fill out all fields.</p>
			<br />
			<label for="city">City</label>
			<input type="text" id="city" required placeholder="city, or latitude and longitude">
			<br />
			<button type="submit">Submit</button>
		</form>
		<p id="thanks" hidden>Your data has been received. Thanks!</p>
		<script>
			const city = document.getElementById('city');
			const thanks = document.getElementById('thanks');
			
			city.onfocus = focus;
			city.oninvalid = invalid;
			city.onblur = blur;
			
			function focus() {
				this.style.background = "#ffff7f";
			}
			
			function blur() {
				this.style.background = "#b8ff9e";
			}
			
			function invalid(event) {
				error.removeAttribute('hidden');
			}
		</script>
	</body>
</html>
  • 焦点事件。

(二)表单提交

当用户单击 Submit 按钮来提交表单或在文本框中输入文本之后按回
车键时,就会触发 onsubmit 事件处理程序。

<!DOCTYPE html>
<html>
	<head>
		<title>FabulousAirTickets.com</title>
	</head>
	<body>
		<form id="form">
			<p id="error" hidden>Please fill out all fields.</p>
			<br />
			<label for="city">City</label>
			<input type="text" id="city" required>
			<br />
			<button type="submit">Submit</button>
		</form>
		<p id="thanks" hidden>Your data has been received. Thanks!</p>
		<script>
			const form = document.getElementById('form');
			const error = document.getElementById('error');
			const city = document.getElementById('city');
			const thanks = document.getElementById('thanks');

			city.oninvalid = invalid;
			form.onsubmit = submit;

			function invalid(event) {
				error.removeAttribute('hidden');
			}

			function submit(event) {
				form.setAttribute('hidden', '');
				thanks.removeAttribute('hidden');

				// For this example, don't actually submit the form
				event.preventDefault();
				return false;
			}
		</script>
	</body>
</html>

  • 在textarea文本区中回车只会换行,不会提交表单。

也能使用formobj.submit()方法提交表单。

浏览器会在将请求发送给服务器之前触发 submit 事件,用户可以有机会验证表单数据,并决定是否允许表单提交。

为了避免用户反复单击提交按钮,可在在第一次提交表单后禁用提交按钮,或者在 onsubmit 事件处理函数中使用event. preventDefault();方法取消表单提交操作。

(三)表单重置

当单击重置按钮时,表单将被重置,所有表单字段恢复为初始值。这时会触发 onreset 事件

<!DOCTYPE html>
<html>
	<head>
		<title>FabulousAirTickets.com</title>
	</head>
	<body>
		<form id="form">
			<p id="error" hidden>Please fill out all fields.</p>
			<br />
			<label for="city">City</label>
			<input type="text" id="city" required style="width: 300px;">
			<br />
			<button type="submit">Submit</button>
			<button type="reset">Reset</button>
		</form>
		<p id="thanks" hidden>Your data has been received. Thanks!</p>
		<script>
			const form = document.getElementById('form');
			const error = document.getElementById('error');
			const city = document.getElementById('city');
			const thanks = document.getElementById('thanks');

			city.oninvalid = invalid;
			form.onsubmit = submit;
			form.onreset = getLocation;

			function invalid(event) {
				error.removeAttribute('hidden');
			}

			function submit(event) {
				form.setAttribute('hidden', '');
				thanks.removeAttribute('hidden');

				// For this example, don't actually submit the form
				event.preventDefault();
				return false;
			}

			function getLocation() {
				if (city.oninvalid) {
					city.oninvalid = function() {};
				}
				if (navigator.geolocation) {
					navigator.geolocation.getCurrentPosition(showPosition);
				} else {
					city.value = "Geolocation is not supported by this browser.";
				}
			}

			function showPosition(position) {
				city.value = "Latitude: " + position.coords.latitude + "  Longitude: " + position.coords.longitude;
			}
		</script>
	</body>
</html>
  • 重置表单时默认填充经纬度。

(四)表单变更

onchange 事件类型是在表单元素的值发生变化时触发。

<!DOCTYPE html>
<html>
	<head>
		<title>Select and Go Navigation</title>
	</head>
	<body>
		<form action="gotoLocation.cgi" class="centered">
			<select id="newLocation">
				<option>——select an option——</option>
				<option value="https://developer.mozilla.org/zh-CN/">MDN1</option>
				<option value="https://developer.mozilla.org/zh-CN/">MDN2</option>
				<option value="https://developer.mozilla.org/zh-CN/">MDN3</option>
				<option value="https://developer.mozilla.org/zh-CN/">MDN4</option>
				<option value="https://developer.mozilla.org/zh-CN/">MDN5</option>
			</select>
			<noscript>
				<input type="submit" value="Go There!">
			</noscript>
		</form>

		<script>
			window.onload = initForm;
			window.onunload = function() {};

			function initForm() {
				document.getElementById("newLocation").selectedIndex = 0;
				document.getElementById("newLocation").onchange = jumpPage;
			}

			function jumpPage() {
				var newLoc = document.getElementById("newLocation");
				var newPage = newLoc.options[newLoc.selectedIndex].value;

				if (newPage != "") {
					window.location = newPage;
				}
			}
		</script>
	</body>
</html>
  • 下拉列表导航。

focus 、 blur 和 change 事件经常配合使用。 一般可以使用 focus 和 blur 事件来以某种方式改变用户界面,要么是向用户给出视觉提示,要么是向界面中添加额外的功能,而 change 事件则经常用于验证用户在宇段中输入的数据。
例如示例设计一个文本框,只允许用户输入数值。此时,可以利用 focus 事件修改文本框的背景颜色,以便更清楚地表明这个字段获得了焦点。可以利用 blur 事件恢复文本框的背景颜色,利用 change 事件在用户输入了非数字字符时再次修改背景颜色。

(五)选择文本

如果用户选择了一个 input 或 textarea 表单区域中的文本,就会触发 onselect 事件

<html>
	<head>

		<title>onselect test</title>

		<style type="text/css">
			.text1 {
				border: 2px solid red;
			}
		</style>

		<script type="text/javascript">
			window.onselect = selectText;

			function selectText() {
				alert("检测到select事件!");
			}
		</script>
	</head>

	<body>
		<textarea class="text1" cols="30" rows="3">用鼠标高亮选择一些文本,来触发select事件</textarea>
	</body>
</html>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值