文章目录
事件处理
早期互联网访问速度是非常慢的,为了避免用户漫长的等待,开发人员尝试把服务器端需要处理的任务部分前移到客户端,让客户端js脚本代替解决,如表单信息验证等。于是在IE3.0和Netscape2.0浏览器中开始出现事件。DOM2规范开始标准化DOM事件,直到2004年发布DOM3.0时,W3C才完善事件模型。
【学习重点】
- 了解事件模型。
- 能够正确注册、销毁事件。
- 掌握鼠标和键盘事件开发。
- 掌握页面和UI事件开发。
- 能够自定义事件。
事件基础
事件流
事件流就是多个节点对象对统一事件进行相应的先后顺序,主要包括以下3种类型。
- 冒泡型
事件从最特定的目标向最不特定的目标(document对象)触发,也就是事件从下向上相应,这个过程被形象称为“冒泡”。
- 捕获型
事件从最不特定的目标(document对象)开始触发,然后到最特定的目标,也就是事件从上到下进行相应。
- 混合型
W3C事件的DOM事件模型支持捕获型和冒泡型两种事件流,其中捕获型事件流先发生,然后才发生冒泡型事件流。两种事件流会触及DOM中的所有层级对象,从document对象开始,最后返回document对象结束。因此,可以把事件传播过程分为3个阶段。
- 捕获阶段:事件从document对象沿着文档树向下传播到目标节点,如果目标节点的任何一个上级节点注册了相同的事件,那么事件在传播的过程中就会首先在最接近顶部的上级节点执行,依次向下传播。
- 目标阶段:注册在目标节点的事件被执行。
- 冒泡阶段:事件从目标节点向上触发,如果上级节点注册了相同的事件,将会逐级响应,依次向上传播。
绑定事件
在基本事件模型中,js支持一下两种绑定方式。
- 静态绑定
把js脚本作为属性值,直接赋予给事件属性。
- 【实例1】下面实例中,把js脚本以字符串的形式传递给onclick属性,为
<button>
标签绑定click事件。当单击按时,就会触发click事件,执行这行js脚本。
<button onclick="alert("你单击了一次");">按钮</button>
- 动态绑定
使用DOM对象的事件属性进行赋值。
- 【实例2】在下面实例中,使用document.getElementById()方法获取button元素,然后把一个匿名函数作为值传递给button元素的onclick属性,实现事件绑定操作。
<button id="btn">按 钮</button>
<script>
var button = document.getElementById("btn");
button.onclick = function(){
alert("你单击了一次");
}
</script>
可以在脚本中直接为元素附加事件,不破坏HTML结构,比上一种方式灵活。
事件处理函数
事件处理函数是一类特殊的函数,与函数直接量结构相同,主要任务是实现事件处理,为异步调用,由事件触发进行相应。
事件处理函数一般没有明确的返回值,不过在特定事件中,用户可以利用事件处理函数的返回值影响程序的执行,如单击超连接时,禁止默认跳转行为。
- 【实例1】下面实例为form元素的onsubmit事件属性定义字符串脚本,设计当文本框中输入值为空时,定义事件处理函数返回值为false。这样将强制表单提交数据。
<form id="form1" name="form1" method="POST" action="http://www.mysite.cn" onsubmit="if(this.elements[0].value.length == 0) return false;">
姓名: <input id="user" name="user" type="text">
<input type="submit" name="btn" id="btn" value="提交">
</form>
在上面代码中,this表示当前form元素,elements[0]表示姓名文本框,如果该文本框的value.length属性值长度为0,表示当前文本框为空,则返回false,禁止提交表单。
事件处理函数不需要参数。在DOM事件模型中,事件处理函数默认包含event参数对象,event对象包含事件信息,在函数内进行传播。
- 【实例2】下面实例会为button对象绑定一个单击事件。参数e为形参,响应事件之后,浏览器会把event对象传递给形参变量a,再把event对象作为一个实参进行传递,读取event对象包含的信息,在事件处理函数中输出当前源对象节点名称。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var button = document.getElementById("btn");
button.onclick = function(e) {
var e = e || window.envent;
document.write(e.srcElement ? e.srcElement : a.target);
}
}
</script>
</head>
<body>
<button id="btn">按钮</button>
</body>
</html>
- 提示:IE事件模型和DOM事件模型对event对象的处理方式不同:IE把event对象定义为window对象的一个属性。而DOM对象把event定义为事件处理函数的默认参数。所以,在处理event参数时,应该判断event在当前解析环境中的状态,如果当前浏览器支持,则使用event(DOM事件模型),如果不支持,则说明当前环境是IE浏览器,通过window.event获取event对象。
event.srcElement表示当前事件的源即响应事件的当前对象,这是IE模型用法。但是DOM事件模型不支持该属性,需要使用event对象的target属性,它是一个符合标准的源属性。为了能够兼容不同浏览器,这里使用了一个条件运算符,先判断event.srcElement属性是否存在,如果不存在则使用event.target属性来获取当前事件对象的源。
在事件处理函数中,this表示当前事件对象,与event对象的ercElement属性(IE模型)或者target(DOM事件模型)属性所代表的意思相同。
- 【实例3】下面实例分别使用this和事件源来指定当前对象,但是会发现this并没有指向当前事件对象按钮,而是指向window对象,所以这个时候继续使用this引用当前对象就错了。
<script>
function btn01() {
this.style.background = 'red';
}
function btn02(event) {
event = event || window.event;
var src = event.srcElement ? event.srcElement : event.target;
src.style.background = 'red';
}
</script>
<button id="btn1" onclick=btn01() type="text/javascript">按钮1</button>
<button id="btn2" onclick=btn02(event) type="text/javascript">按钮2</button>
为了能够准确获取当前事件对象,在第二个按钮的click事件处理函数中直接把event传递给btn2()。如果不传递该参数,支持DOM事件模型的浏览器就会找不到event对象。
注册事件
在DOM事件模型中,通过调用对象的addEventListener()方法注册事件。用法如下:
element.addEventListener(String type, Function listener, boolean useCapture);
参数说明:
-
type:注册时间的类型名。事件类型与事件属性不同,事件类型名没有on前缀。例如,对于事件属性onclick来说,所对应的事件类型为click。
-
listener:监听函数,即事件处理函数。在指定类型的事件发生时将调用该函数。在调用这个函数时,默认传递给它一个唯一参数是event对象。
-
useCapture:是一个布尔值。如果为true,则指定的事件处理函数在事传播的捕获阶段触发;如果为false,则事件处理函数将在冒泡阶段触发。
-
【实例1】下面实例使用addEventListener()为所有按钮注册click事件,首先调用getElementsByTagName()方法获取所有按钮对象;然后,使用for语句遍历按钮集(btn),并使用addEventListener()方法分别为每一个按钮注册事件函数,获取当前对象所显示的文本。
<script>
var btn = document.getElementsByTagName("button");
for (var i in btn) {
btn[i].addEventListener("click", function() {
alert(this.innerHTML);
}, true);
}
</script>
<button id="btn1">按钮1</button>
<button id="btn2">按钮2</button>
在浏览器浏览点击不同按钮,则浏览器会自动显示按钮名称。
使用addEventListener()方法能够为多个对象注册相同的事件处理函数,也可以为同一个对象注册多个事件处理函数。为同一个对象注册多个事件处理函数对于模块化开发非常有用。
销毁事件
在DOM事件模型中,使用removeEventListener()方法可以从指定对象中删除已经注册的事件处理函数。
element.removeEventListener(String type, Function listener, boolean useCapture);
- 【实例1】在下面实例中,分别为按钮a和按钮b注册click事件,其中按钮a的事件函数为ok(),按钮b的事件函数为delete_event()。在浏览器中浏览,当单击“点我”按钮将弹出一个对话框,在不删除之前这个事件时一直存在。当单击“删除事件”按钮之后,“点我”按钮将失去任何效果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var a = document.getElementById("a");
var b = document.getElementById("b");
function ok() {
alert("您好,欢迎光临");
}
function delete_event() {
a.removeEventListener("click", ok, false);
}
a.addEventListener("click", ok, false);
b.addEventListener("click", delete_event, false);
}
</script>
</head>
<body>
<input type="button" id="a" value="点我">
<input type="button" id="b" value="删除事件">
</body>
</html>
-
removeEventListener()方法只能删除addEventListener()方法注册的事件。如果使用onclick等直接写在元素上的事件,将无法使用removeEventListener()方法删除。
-
当临时注册一个事件时,可以在处理完毕之后迅速删除它,这样能够节省系统资源。
-
IE事件模型使用detachEvent()方法注销事件。
element.detachEvent(etype, eventName);
由于IE怪异模式不支持DOM事件模型,为了保证页面的兼容性,开发时需要兼容两种事件模型,以实现在不同浏览器中具有相同的交互行为。
使用event对象
event对象由事件自动创建,记录了当前事件的状态,如事件发生的源节点、键盘按键的响应状态、鼠标指针的移动位置、鼠标按键的响应状态等信息。event对象的属性提供了有关事件的细节,其方法可以控制事件的传播。
2级DOM Events规范定义了一个标准的事件模型,它除被IE怪异模式以外的所有现代浏览器所实现,而IE定义了专用的、不兼容的模型。简单比较两种事件模型如下:
- 在DOM事件模型中,event对象被传递给事件处理函数,但是在IE事件模型中,它被存储在window对象的event属性中。
- 在DOM事件模型中,Event类型的各种子接口定义了额外的属性,它们提供了与特定事件类型相关的细节,在IE事件模型中,只有一种类型的event对象,它用于所有类型的事件。
下面列出2级DOM事件标准定义的event对象属性。
属性 | 说明 |
---|---|
bubbles | 返回布尔值,指示事件是否是冒泡事件类型。 |
cancelable | 返回布尔值,指示事件是否可以取消的默认动作。 |
currentTarget | 返回触发事件的当前节点,即当前处理该事件的元素、文档或窗口。 |
eventPhase | 返回事件的当前阶段,包括捕获阶段、目标事件阶段、冒泡阶段。 |
target | 返回事件的目标节点,如生成事件的元素、文档或窗口 |
timeStamp | 返回事件的日期和时间。 |
type | 返回当前event对选哪个表示的事件的名称。如“submit”“load”或“click”。 |
下面列出2级DOM事件标准定义的event对象方法。
方法 | 说明 |
---|---|
initEvent() | 初始化新建的event对象的属性。 |
preventDefault() | 通知浏览器不要执行与事件关联的默认动作。 |
stopPropagation() | 终止事件在传播过程的捕获、目标处理或冒泡阶段进一步传播。调用该方法后,该节点上处理事件的处理函数将被调用,但事件不再被分派到其他节点。 |
在事件驱动为核心的设计模型中,一次只能处理一个事件,由于从来不会并发两个事件,因此使用全局变量来存储事件信息是一种比较安全的方法。
- 【实例】下面实例演示了如何禁止超链接默认的跳转行为。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
document.getElementById("a1").onclick = function(e) {
e = e || window.event;
var target = e.target || e.srcElement;
if (target.nodeName !== 'A') {
return;
}
if (typeof e.preventDefault === 'function') {
e.preventDefault();
e.stopPropagation();
} else {
e.returnValue = false;
e.cancelBubble = true;
}
}
}
</script>
</head>
<body>
<a href="https://www.baidu.com/" id="a1">禁止超链接跳转</a>
</body>
</html>
事件委托
事件委托(delegate)也称为事件托管或事件代理,就是把目标节点的时事件绑定到祖先节点上。这种简单而优雅的事件注册是基于事件传播过程中,逐层冒泡总能被祖先节点捕获。
这样做的好处:优化代码,提升运行性能,真正把HTML和js分离,也能防止出现在动态添加或删除节点过程中注册的事件丢失的现象。
- 【实例1】下面实例使用一般方法为列表结构中每个列表项目绑定click事件,单击列表项目,将弹出提示对话框,提示当前节点包括的文本信息,但是,当我们为列表框动态添加列表项目之后,新增加的列表项目没有绑定click事件,这与我们的愿望相反。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var ul = document.getElementById("list·");
var lis = ul.getElementsByTagName("li");
for (var i = 0; i < lis.length; i++) {
lis[i].addEventListener("click", function(e) {
var e = e || window.event;
var target = e.target || e.srcElement;
alert(e.target.innerHTML);
}, false);
}
var i = 4;
var btn = document.getElementById("btn");
btn.addEventListener("click", function() {
var li = document.createElement("li");
li.innerHTML = "列表项目" + i++;
ul.appendChild(li);
});
}
</script>
</head>
<body>
<button id="btn">添加列表项目</button>
<ul id="list">
<li>列表项目1</li>
<li>列表项目2</li>
<li>列表项目3</li>
</ul>
</body>
</html>
- 【实例2】下面实例借助事件委托技巧,利用事件传播机制,在列表ul元素上绑定click事件,当事件传播到父节点ul上时,捕获click事件,然后在事件处理函数中检测当前事件响应节点类型,如果是li元素,则进一步执行下面代码,否则跳出事件处理函数,结束响应。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var ul = document.getElementById("list");
ul.addEventListener('click', function(e) {
var e = e || window.event;
var target = e.target || e.srcElement;
if (e.target && e.target.nodeName.toUpperCase() == "LI") {
alert(e.target.innerHTML);
}
}, false);
var i = 4;
var btn = document.getElementById("btn");
btn.addEventListener("click", function() {
var li = document.createElement("li");
li.innerHTML = "列表项目" + i++;
ul.appendChild(li);
});
}
</script>
</head>
<body>
<button id="btn">添加列表项目</button>
<ul id="list">
<li>列表项目1</li>
<li>列表项目2</li>
<li>列表项目3</li>
</ul>
</body>
</html>
当页面存在大量元素并且每个元素注册了一个或多个事件时,可能会影响。访问和修改更多的DOM节点时,程序就会更慢;特别是事件连接过程都发生在load(或DOMContentReady)事件中时,对任何一个富交互页面说,这都是一个繁忙的时间段。另外,浏览器需要保存每个事件句柄的记录,也会占用更多内存。
使用鼠标事件
鼠标事件时Web开发中最常用的事件类型,鼠标事件类型说明:
事件类型 | 说明 |
---|---|
click | 单击鼠标左键时发生,如果右键也同时按下则不会发生。当用户的焦点在按钮上并按了Enter键时,同样会触发这个事件。 |
dbclick | 双击鼠标左键时发生,如果右键也按下则不会发生。 |
mousedown | 单击任意一个鼠标按钮时发生。 |
mouseover | 鼠标指针移出某个元素到另一个元素时发生。 |
mouseout | 鼠标指针位于某个元素且将要移出元素的边界时发生。 |
mouseup | 松开热议一个鼠标按钮时发生。 |
mousemove | 鼠标在某个元素上持续发生。 |
- 【实例】在下面实例中,定义在段落文本范围内侦测鼠标的各种动作,并在文本框中实时显示各种事件的类型,以提示当前用户行为。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var p1 = document.getElementsByTagName("p")[0];
var t = document.getElementById("text");
function f() {
var event = event || window.event;
t.value = (event.type);
}
p1.onmouseover = f;
p1.onmouseout = f;
p1.onmousedown = f;
p1.onmouseup = f;
p1.onmousemove = f;
p1.onclick = f;
p1.ondbclick = f;
}
</script>
</head>
<body>
<p>鼠标事件</p>
<input type="text" id="text">
</body>
</html>
鼠标点击
鼠标点击事件包括4个:click(单击)、dbclick(双击)、mousedown(按下)、mouseup(松开)。其中click事件类型比较常用,而mousedown和mouseup事件类型多用在鼠标释放、拉伸操作中。当这些事件处理函数的返回值为false时,会禁止绑定对象的默认行为。
- 【实例】在下面实例中,当定义超链接指向自身时(多在设计过程中href属性值暂时使用“#”或“?”表示),可以取消超链接被单击的默认行为,即刷新页面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var a = document.getElementsByTagName("a");
for (var i = 0; i < a.length; i++) {
if ((new RegExp(window.location.href)).test(a[i].href)) {
// 如果当前超链接href属性中包含页面的URL信息
a[i].onclick = function() {
return false;
}
}
}
}
</script>
</head>
<body>
<a href="#" name="tag" id="tag">a</a>
</body>
</html>
当单击实例中的超链接,页面不会发生跳转变化(即禁止页面发生刷新效果)。
鼠标移动
mousemove事件类型是一个实时响应的事件,当鼠标指针的位置发生变化时(至少移动一个像素),就会触发mousemove事件。该事件响应的灵敏度主要参考鼠标指针移动速度的快慢,以及浏览器跟踪更新的速度。
- 【实例】下面实例演示了如何综合应用各种鼠标事件实现页面元素拖放操作的设计实现,实现拖放操作设计需要解决以下几个问题。
- 定义拖放元素为绝对定位以及设计事件的响应过程,这个比价容易实现。
- 清楚几个坐标概念:按下鼠标时的指针坐标,移动中当前鼠标的指针坐标,松开鼠标时的指针坐标,拖放元素的原始坐标,拖动中的元素坐标。
- 算法设计:按下鼠标时,获取被拖放元素和鼠标指针的位置,在移动中实时计算书标偏移的距离,利用该偏移距离加上被拖放元素的原坐标位置,获得拖放元素的实时坐标。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
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) {
event = window.event;
event.target = event.srcElement;
event.layerX = event.offsetX;
event.layerY = event.offsetY;
}
event.mx = event.pageX || event.clientX + document.body.srcollLeft;
// 计算鼠标指针的x轴距离
event.my = event.pageY || event.clientY + document.body.scrollYop;
// 计算鼠标指针的y轴距离
return event;
}
// 定义鼠标事件处理函数
document.onmousedown = function() {
event = e(event);
o = event.target;
ox = parseInt(o.offsetLeft);
oy = parseInt(o.offsetTop);
mx = event.mx;
my = event.my;
document.onmousemove = move;
document.onmouseup = stop;
}
function move(event) {
event = e(event);
o.style.left = ox + event.mx - mx + "px";
o.style.top = oy + event.my - my + "px";
}
function stop(event) {
event = e(event);
ox = parseInt(o.offsetLeft);
oy = parseInt(o.offsetTop);
mx = event.mx;
my = event.my;
o = document.onmousemove = document.onmouseup = null;
}
}
</script>
</head>
<body>
<div id="box"></div>
</body>
</html>
鼠标经过
鼠标经过包括移过和移出两种事件类型。当移动鼠标指针到某个元素上时,将触发mouseover事件;而当把鼠标指针移出某个元素时,将触发mouseout事件。如果从父元素中移到子元素中时,也会触发父元素的mouseover事件类型。
- 【实例】在下面实例中分别为3个嵌套的div元素定义了mouseover和mouseout事件处理函数,这样当从外层的父元素中移动到内部的子元素中时,将会触发父元素的mouseover事件类型,但是不会触发mouseout事件类型。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var div = document.getElementsByTagName("div");
for (var i = 0; i < div.length; i++) {
div[i].onmouseover = function(e) {
this.style.border = "solid blue";
}
div[i].onmouseout = function() {
this.style.border = "solid red";
}
}
}
</script>
</head>
<body>
<div>
<div>
<div>盒子</div>
</div>
</div>
</body>
</html>
鼠标来源
当一个事件发生后,可以使用事件对象的target属性获取发生事件的节点元素。如果在IE事件模型中实现相同的目标,可以使用srcElement属性。
- 【实例1】在下面实例中当鼠标移过页面中的div元素时,会弹出提示对话框,提示当前元素的节点名称。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var div = document.getElementsByTagName("div")[0];
div.onmouseover = function(e) {
var e = e || window.event;
var o = e.target || e.srcElement;
alert(o.tagName);
}
}
</script>
</head>
<body>
<dib>div元素</dib>
</body>
</html>
在DOM事件模型中还定义了currentTarget属性,当事件在传播过程中(如捕获和冒泡阶段)时,该属性值与target属性值不同。因此,一般在事件处理函数中,应该使用该属性而不是this关键词获取当前对象。
除了使用上面提到的同样事件属性外,如果想获取鼠标指针来移动某个元素,在DOM事件模型中可以使用relatedTarget属性获取当前事件对象的相关节点元素;而在IE事件模型中,可以使用fromElement获取mouseover事件中鼠标移到过的元素,使用toElement属性获取在mouseout事件中鼠标移到的文档元素。
- 【实例2】在下面实例中,当鼠标移到div元素上时,会弹出“BODY”字符提示,说明鼠标指针是从body元素过来的,而移开鼠标指针时,又弹出“BODY”字符提示信息,说明离开div元素将要移到的元素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var div = document.getElementsByTagName("div")[0];
div.onmouseover = function(e) {
var e = e || window.event;
var o = e.relatedTarget || e.fromElement;
alert(o.tarName);
}
div.onmouseout = function(e) {
var e = e || window.event;
var o = e.relatedTarget || e.toElement;
alert(o.tarName);
}
}
</script>
</head>
<body>
<dib>div元素</dib>
</body>
</html>
鼠标定位
当事件发生时,获取鼠标的位置是件很重要的事件。由于浏览器不兼容性,不同浏览器分别在各自事件对象中定义了不同的属性。这些属性都要以像素值定义了鼠标指针的坐标,但是由于它们参照的坐标系不同,导致准确计算鼠标的位置比较麻烦。
属性 | 说明 | 兼容性 |
---|---|---|
clientX | 以浏览器窗口左上角为原点,定位x轴坐标 | 所有浏览器,不兼容safari |
clientY | 以浏览器窗口左上角为原点,定位y轴坐标 | 所有浏览器,不兼容safari |
offsetX | 以当前事件的目标对象左上顶角为原点,定位x轴坐标 | 所有浏览器,不兼容Mozilla |
offsetY | 以当前事件的目标对象左上顶角为原点,定位y轴坐标 | 所有浏览器,不兼容Mozilla |
pageX | 以document对象(即文档窗口)左上顶角为原点,定位x轴坐标 | 所有浏览器,不兼容IE |
pageY | 以document对象(即文档窗口)左上顶角为原点,定位y轴坐标 | 所有浏览器,不兼容IE |
screenX | 计算机屏幕左上顶角为原点,定位x轴坐标 | 所有浏览器 |
screenY | 计算机屏幕左上顶角为原点,定位y轴坐标 | 所有浏览器 |
layerX | 最近的绝对定位的父元素(如果没有,则为document对象)左上顶角,定位x轴坐标 | Mozilla和Safari |
layerY | 最近的绝对定位的父元素(如果没有,则为document对象)左上顶角,定位x轴坐标 | Mozilla和Safari |
- 【实例】封装鼠标定位代码。设计思路:能够根据传递的具体对象,以及相对鼠标指针的偏移量,命令该对象能够跟随鼠标移动。
- 先定义一个封装函数,设计函数传入参数为对象引用指针、相对鼠标指针的偏移距离,以及事件对象。然后封装函数能够根据事件对象获取信息的坐标值,并设置该对象为绝对定位,绝对定位的值为鼠标指针当前的坐标值。
封装代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
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 + docuemnt.documentElement.scrollLeft + document.body.scrollLeft;
posY = e.clientY + docuemnt.documentElement.scrollTop + document.body.scrollTop;
}
o.style.postion = "absolute";
o.style.top = (posY + y) + "px";
o.style.left = (posX + x) + "px";
}
var div1 = document.getElementById("div1");
document.onmousemove = function(event) {
pos(div1, 10, 20, event)
}
}
</script>
</head>
<body>
<div id="div1">鼠标跟随</div>
</body>
</html>
鼠标按键
通过事件对象的button属性可以获取当前鼠标按下的键,该属性可用于click、mousedown、mouseup事件类型。不过不同模型约定不同。
单击 | IE事件模型 | DOM事件模型 |
---|---|---|
左键 | 1 | 0 |
右键 | 2 | 2 |
中键 | 4 | 1 |
IE事件模型支持掩码技术,它能够侦测到同时按下的多个键。例如,同时按下左右键,则button属性值为1+2=3;同时按下中键和右键,则button属性值为2+4=6;同时按下左键和中键,则button属性值为1+4=5,同时按下3个键,则button属性值为1+2+4=7;
但是DOM事件模型不支持掩码技术,如果同时按下多个键,就不能够精准侦测。例如同时按下左键和右键(0+2=2)和只按下右键(2)的值是相同的 。因此,对于DOM模型来说,这种button属性约定值存在很大的缺陷。不过,在实际开发中很少需要同时检测多个鼠标按钮问题,一般仅需要探测鼠标左键或右键点击行为。
- 【实例】下面代码能够检测右键单击操作,并阻止发生默认行为。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
document.onclick = function(e) {
var e = e || window.event;
if (e.button == 2) {
e.preventDefault();
return false;
}
}
}
</script>
</head>
<body>
<div id="div1">鼠标跟随</div>
</body>
</html>
- 提示:当鼠标点击事件发生时,会触发很多事件:mousedown、mouseup、click、dbclick。这些事件响应的顺序如下:
- mousedown>mouseup>click>mousedown>mouseup>click>dbclick
- 当鼠标在对象间移动时,首先触发的事件是mouseout,即在鼠标移出某个对象时发生。接着,在这两个对象上都会触发mousemove事件。最后,在鼠标进入对象上触发mouseover事件。
使用键盘事件
当用户操作键盘时会触发键盘事件,键盘事件主要包括下面3种类型。
- keydown:在键盘上按下某个键时触发。如果按住某个键,会不断触发该事件,但是Opera浏览器不支持这种连续操作。该事件处理函数返回false时,会取消默认的动作(如输入的键盘字符,在IE和Safari浏览器下还会禁止keypress事件响应)。
- keypress:按下某个键盘并释放时触发。如果按住某个键,会不断触发该事件。该事件处理函数返回false时,会取消默认的动作(如输入的键盘字符)。
- keyup:释放某个键盘时触发。该事件仅在松开键盘时触发一次,不是一个持续的响应状态。
当获知用户正按下键码时,可以使用keydown、keypress和keyup事件获取这些信息。其中keydown和keypress事件基本上是同义事件,他们的表现也完全一致,不过一些浏览器不允许使用keypress事件获取按钮信息。所有元素都支持键盘事件,但键盘事件多被应用在表单输入中。
- 【实例】下面实例实现捕获键盘操作的各种细节,即键盘响应响应类型及对应的键值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var key = document.getElementById("key");
key.onkeydown = f;
key.onkeyup = f;
key.onkeypress = f;
function f(e) {
var e = e || window.event;
var s = e.type + " " + e.keyCode;
key.value = s;
}
}
</script>
</head>
<body>
<textarea id="key"></textarea>
</body>
</html>
键盘事件属性
键盘事件定义了很多属性,利用这些属性可以精确控制键盘操作。键盘事件属性一般只在键盘相关事件发生时才会存在于事件对象中,但是ctrlKey和shiftKey属性除外,因为它们可以在鼠标事件中存在。例如当按下Ctrl或Shift键时单击鼠标操作。
属性 | 说明 |
---|---|
keyCode | 该属性中包含键盘中对应键位的键值。 |
charCode | 该属性中包含键盘中对应键位的Unicode编码,仅DOM支持 |
target | 发生事件的节点(包含元素),仅DOM支持。 |
srcElement | 发生事件的元素,仅IE支持。 |
shiftKey | 是否按下Shift键,如果按下返回true,否则为false。 |
ctrlKey | 是否按下Ctrl键,如果按下返回true,否则为false。 |
altKey | 是否按下Alt键,如果按下返回true,否则为false。 |
metaKey | 是否按下Meta键,如果按下返回true,否则为false,仅DOM支持。 |
- 【实例1】ctrlKey和shiftKey属性可存在于键盘和鼠标事件中,表示键盘上的Ctrl和Shift键是否被按住。下面实例能够检测Ctrl和Shift键是否被同时按下。如果同时按下,且鼠标单击某个页面元素,则会把该元素从页面中删除。
document.onclick = function(e){
var e = e || window.event;
var t = e.target || e.srcElement;
if(e.ctrlKey && e.shiftKey) {
t.parentNode.removeChild(t);
}
}
keyCode和charCode属性使用比较复杂,但是它们在实际开发中又比较常用,故比较这两个属性在不同事件类型和不同浏览器的表现是非常有必要的。
属性 | IE事件模型 | DOM事件模型 |
---|---|---|
keyCode(keypress) | 返回所有字符键的正确值,区分大写状态(65-90)和小写状态(97-122) | 功能键返回正确值,而shift、ctrl、alt、printscreen、scrlllock无返回值,其他所有键值返回0 |
keyCode(keydown) | 返回所有键值(除Printscreen键),字母键都以大写状态显示(65-90) | 返回所有键值(除printscreen),字母键都以大写状态显示键值(65-90) |
keyCode(keyup) | 返回所有键值(除Printscreen键),字母都以大写状态显示键值(65-90) | 返回所有键值(除PrintScreen键),字母都以大写状态显示键值(65-90) |
charCode(keypress) | 不支持该属性 | 返回字符键,区分大写状态(65-90)和小写状态(97-122),shift、ctrl、alt、Printscreen、scrlllock键无返回值,其他所有键值为0 |
charCode(keydown) | 不支持该属性 | 所有键值为0 |
charCode(keyup) | 不支持该属性 | 所有j键值为0 |
某些键的可用性不是很确定,如pageUp和Home键等。不过常用功能键和字符键都比较稳定。
键位 | 码值 |
---|---|
0~9(数字键) | 48~57 |
Backspace(退格键) | 8 |
Enter(回车) | 13 |
Left arrow(左箭头键) | 37 |
Right arrow(右箭头键) | 39 |
A~Z(字母键) | 65~90 |
Tab(制表键) | 9 |
Space(空格键) | 32 |
Top arrow(上箭头键) | 38 |
Down arrow(下箭头键) | 40 |
- 【实例2】下面实例演示了如何使用方向键控制页面元素的移动效果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var box = document.getElementById("box");
box.style.position = "absolute";
box.style.width = "20px";
box.style.height = "20px";
box.style.backgroundColor = "red";
document.onkeydown = keyDown;
function keyDown(event) {
var event = event || window.event;
switch (event.keyCode) {
case 37:
box.style.left = box.offsetLeft - 5 + "px";
break;
case 39:
box.style.left = box.offsetLeft + 5 + "px";
break;
case 38:
box.style.top = box.offsetTop - 5 + "px";
break;
case 40:
box.style.top = box.offsetTop + 5 + "px";
break;
}
return false;
}
}
</script>
</head>
<body>
<div id="box"></div>
</body>
</html>
在上面实例中,首先获取页面元素,通过CSS脚本控制元素绝对定位、大小和背景色。然后在document对象上注册鼠标按下事件类型处理函数,在事件回调函数keyDown()中侦测当前按下的方向键,并决定定位元素在窗口个中的位置。其中元素的offsetLeft和offsetTop属性可以存取它在页面中的位置。
键盘响应顺序
当按下键盘时,会连续触发多个事件,他们将按如下顺序发生。
对于字符键来说,键盘响应的响应顺序:keydown->keypress->keyup。
对于非字符键(如功能键和特殊键)来说,键盘事件的响应顺序:keydown->keyup。
如果按下字符键不放,则keydown和keypress事件将逐个持续发生,直到松开键盘键。
如果按下非字符键不放,则是有keydown事件持续发生,直至松开按键。
- 【实例】下面设计一个简单实例,以获取键盘事件响应顺序。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var n = 1;
var text = document.getElementById("text");
text.onkeydown = f;
text.onkeyup = f;
text.onkeypress = f;
function f(e) {
var e = e || window.event;
text.value += (n++) + "=" + e.type + " (keyCode=" + e.keyCode + ")\n"; //捕获响应信息
}
}
</script>
</head>
<body>
<textarea name="" id="text" cols="26" rows="16"></textarea>
</body>
</html>
使用页面事件
所有页面事件都明确地处理整个页面的函数和状态。主要包括页面的加载和卸载,即用户访问页面和离开关闭页面的事件类型。
页面初始化
load事件类型在页面完全加载完毕的时候触发。该事件包含所有的图形图像、外部文件(CSS、JS文件等)的加载,也就是说,在页面所有内容全部加载之前,任何DOM操作都不会发生。为window对象绑定load事件类型的方法有两种。
- 方法一:直接为window对象注册页面初始化事件处理函数。
window.onload = f;
function f (){
alert("页面加载完毕");
}
- 方法二:在页面
<body>
标签中定义onload事件处理属性。
<body onload = f>
<script>
function f(){
alert("页面加载完毕");
}
</script>
如果发现同时使用两种方法定义load事件类型,会使用window对象注册的事件处理函数覆盖掉body元素定义的页面初始化事件属性。
在实际开发中,load事件类型经常需要调用附带参数的函数,但是load事件类型不能够直接调用函数,要解决这个问题,有以下两种方法。
- 方法一:在body元素中通过事件属性的形式调用函数。
<body onload="f1()">
<script>
function f(a) {
alert(a);
}
</script>
- 方法二:通过函数嵌套或闭包来实现。
windowo.onload = function(){
f("Hi");
}
function f(a){
alert(a);
}
也可以采用闭包函数形式,这样在注册事件时,虽然调用的是函数,但是其返回值已然是一个函数不会引发语法错误。
window.onload = f("Hi");
function f(a) {
return function(){
alert(a);
}
}
结构初始化
在传统事件模型中,load是页面中最早被触发的事件。不过当使用load事件来初始化页面时可能会存在一个问题,就是当页面中包含很大的文件时,load事件需要等到所有图像全部载入完成之后才会被触发。也许用户希望某些脚本能够在页面结构加载完毕之后就能被执行。作为DOM标准事件,它是在DOM文档结构加载完毕的时候触发的,因此要比load事件类型先被触发。目前,Mozilla和Opera新版本已经支持了该事件而IE和Safari浏览器还不支持。
- 【实例1】如果在标准DOM中,可以这样设计。
<script>
window.onload = f1;
if (document.addEventListener) {
documentn.addEventListener("DOMContentLoaded", f, false);
}
function f() {
alert("我提前执行了");
}
function f1() {
alert("页面初始化完毕");
}
</script>
<body>
<img src="../img/kiki.jpg" alt="">
</body>
这样图片加载之前会弹出“我提前执行了的提示信息”,而当图片加载完毕之后彩会弹出“页面初始化完毕”提示信息。这说明在页面HTML结构加载完毕之后触发DOMContentLoaded事件类型,也就是说,在文档标签加载完毕时触发该事件并调用f(),然后,当文档所有内容加载完毕(包括图片下载完毕)时才会触发load事件类型,并调用函数f1()。
页面卸载
unload表示卸载的意思,这个事件在从当前浏览器窗口内移动文档的位置时触发,也就是说,通过超链接、前进或后退按钮等方式从一个页面跳转到其他页面,或者关闭浏览器窗口时触发。
- 【实例】下面函数的提示信息将在卸载页面时发生,即在离开页面或关闭窗口前执行。
window.onunload = f2;
function f2() {
alert("888");
}
在unload事件类型中无法有效阻止默认行为,因为该事件结束后,页面将不复存在。由于在窗口关闭或离开页面之前只有很短的时间来执行事件处理函数,所以不建议使用该事件了性。使用该事件类型的最佳方式是取消该页面的对象引用。
- 提示:
beforeunload事件类型与unload事件类型的功能相近,不过它更人性化,如果beforeunload事件处理函数返回字符串信息,那么字符串会显示一个在确认对话框中,询问用户是否离开当前页面。
window.onbeforeunload = function(e) {
return "您的数据还没有保存呢!?";
}
beforeunload事件处理函数返回值可以为任意类型,IE和Safari浏览器的JavaScript解释器能够调用toString()方法,并把它转换为字符串显示在提示对话框中;而对于Mozilla浏览器来说,则会视为空字符串显示。如果beforeunload事件处理函数没有返回值,则不会弹出任何提示对话框,此时unload事件类型响应效果相同。
窗口重置
resize事件类型是在浏览器窗口被重置时触发的,如果用户调整窗口大小,或者最大化、最小化、回复胡沧口大小显示时触发resize事件。利用该事件可以跟踪窗口大小的变化以便动态调整页面元素的大小。
- 【实例】下面的实例能够跟踪窗口大小变化及时调整页面内红色盒子的大小,使其时钟保持与窗口固定比例的大小显示。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
<script>
window.onload = function() {
var box = document.getElementById("box");
box.style.position = "absolute";
box.style.backgroundColor = "red";
box.style.width = w() * 0.8 + "px";
box.style.height = h() * 0.8 + "px";
window.onresize = function() {
box.style.width = w() * 0.8 + "px";
box.style.height = h() * 0.8 + "px";
}
function w() {
if (window.innerWIdth) {
return window.innerWidth;
} else if ((document.body) && (document.body.clientWidth)) {
//兼容IE
return document.body.clientWidth;
}
}
function h() {
if (window.innerHeight) {
return window.innerHeight;
} else if ((document.body) && (document.body.clientHeight)) {
return document.body.clientHeight;
}
}
}
</script>
</head>
<body>
<div id="box"></div>
</body>
</html>
页面滚动
scroll事件类型用于在浏览器窗口内移动文档的触发,如通过键盘箭头键、翻页键或空格键移动文档位置,或者通过滚动条移动文档位置。利用该事件可以跟踪文档位置变化,及时调整某些元素的显示位置,确保它时钟显示在屏幕可见区域中。
- 【实例】在下面实例中,控制红色小盒子始终位于坐标为(100px,100px)的位置。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<div id="box"></div>
<div style="height: 2000px;width: 2000px;"></div>
</body>
<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>
</html>
还有一种方法,就是利用settimeout()函数实现每间隔一定时间校正一次元素的位置,不过这种方法的损耗比较大,不建议选用。
错误处理
error事件类型是在js代码发生错误时处触发的,利用该事件可以捕获并处理错误信息。error事件类型与try/catch语句功能相似,都用来捕获页面错误信息。不过error事件类型无需传递事件对象。且可以包含已经发生错误的解释信息。
- 【实例】下面实例中,当页面编译错误时,将会触发error事件注册的事件处理函数,并弹出错误信息。
window.onerror = function(message) {
alert("错误原因:" + arguments[0] +
"\n错误URL:" + arguments[1] +
"\n错误行号:" + arguments[2]
);
return true;
}
a.innerHTML = "";
在error事件处理函数中,默认包含3个参数:其中第一个参数表示错误信息,第二个参数表示出错文件的URL,第三个参数表示文件中错误位置的行号。
error事件处理函数的返回值可以决定浏览器是否显示一个标准出错信息。如果返回值为false,则浏览器不会显示标准出错信息。
使用UI事件
用户界面(User Interface, UI)事件负责响应用户与页面元素的交互。
焦点处理
焦点处理主要包括获取焦点(focus)和失去焦点(blur)事件类型。所为焦点,就是激活表单字段,使其可以响应键盘事件。
- focus
当单击或使用Tab键切换到某个表单元素或超链接对象时,会触发该事件。focus事件是确定页面内鼠标当前定位的一种方式。在默认情况下,整个文档处于焦点状态,但是单击或使用Tab键可以改变焦点的位置。
- blur
blur事件类型表示在元素失去焦点时响应,它与focus事件类型是对应的,主要作用于表单元素和超链接对象。
- 【实例1】下面实例中为所有输入表单元素绑定了focus和blur事件处理函数,设置当元素获取焦点时,呈凸起显示,失去焦点时则显示为默认的凹陷效果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<input type="text">
<input type="text">
</body>
<script>
var o = document.getElementsByTagName("input");
for (var i = 0; i < o.length; i++) {
o[i].onfocus = function() {
this.style.borderStyle = "outset";
}
o[i].onblur = function() {
this.style.borderStyle = "inset";
}
}
</script>
</html>
每个表单字段都有两个方法:focus()和blur(),其中focus()方法用于设置表单字段为焦点。
- 【实例2】在下面实例中设计在页面加载完毕后将焦点转移到表单中的第1个文本框字段中,让其准备接收用户输入。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<form action="#" id="myform" method="POST">
姓名<input type="text" name="name"><br> 密码
<input type="password" name="pass">
</form>
</body>
<script>
var form = document.getElementById("myform");
var field = form.elements["name"];
window.onload = function() {
field.focus();
}
</script>
</html>
选择文本
当文本框或文本框内选择文本时,将触发select事件。通过该事件,可以设计用户选择操作的交互行为。
在IE9+、Opera、Firefox、Chrome和Safari中,只有选择了文本且释放鼠标,才会触发select事件;但是在IE8以及更早的版本,只要用户选择了一个字母,不必释放鼠标,就会触发select事件。另外,在调用selecte()方法也会触发select事件。
- 【实例1】下面的实例中当选择第一个文本框中的文本时,则在第2个文本框中会动态显示用户所选择的文本。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<input type="text" id="a" value="请随意选择字符串">
<input type="text" id="b">
</body>
<script>
var a = document.getElementById("a");
var b = document.getElementById("b");
a.onselect = function() {
if (document.selection) {
o = document.selection.createRange();
if (o.text.length > 0) {
b.value = o.text;
}
} else {
p1 = a.selectionStart;
p2 = a.selectionEnd;
b.value = a.value.substring(p1, p2);
}
}
</script>
</html>
字符值变化检测
change事件类型是在表单元素的值发证变化时触发,它主要用于input、select和textarea元素。对于input和textarea元素来说,当它们失去焦点且value值发生改变时触发;对于select元素,在其选项改变是=时触发,也就是说不失去焦点也会触发change事件。
- 【实例1】在下面实例中,当在1和文本框中输入或修改值时,则第2个文本框内会立即显示第1个文本框的当前值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<input type="text" id="a">
<input type="text" id="b">
</body>
<script>
var a = document.getElementById("a");
var b = document.getElementById("b");
a.onchange = function() {
b.value = a.value;
}
</script>
</html>
- 【实例2】下面实例演示了当在下拉列表中选择不同的网站时,会自动打开该网站的首页。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<select name="" id="">
<option value="http://www.baidu.com/">百度</option>
<option value="http://www.google.cn/">Google</option>
</select>
</body>
<script>
var a = document.getElementsByTagName("select")[0];
a.onchange = function() {
window.open(this.value, "");
}
</script>
</html>
对于input元素来说,由于change事件类型仅在用户已经离开了元素且失去了焦点时触发,所以当执行上面实例会明显感觉延迟。为了更好的提高用户体验,很多时候会根据需要定义在按键松开或鼠标单击时响应,这样速度会快很多。
focus、blur和change事件经常配合使用。一般可以使用focus和blur事件来以某种方式改变用户界面,要么是向用户给出视觉提示,要么是向界面中添加额外的功能。例如,文本框显示一个下拉选项菜单。而change事件经常用于验证用户在字段中输入的数据。
- 【实例3】下面实例设计一个文本框,只允许用户输入数值。此时,可以利用focus事件修改文本框的背景颜色,以便更清楚的表明这个字段获得了焦点。可以利用blur事件恢复文本框的背景颜色,利用change事件在用户输入了非数字字符时再次修改背景颜色。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<form action="javascript:alert('表单提交啦!')" method="POST" id="myform">
<p>
<label for="txtNumbers">请输入数字:</label><br>
<input type="text" id="txtNumbers" name="numbers">
</p>
<p><input type="submit" value="提交表单" id="submit-btn"></p>
</form>
</body>
<script>
var form = document.getElementById("myform");
var numbers = form.elements["numbers"];
numbers.onfocus = function(event) {
event = event || window.event;
var target = event.target || event.srcElement;
target.style.backgroundColor = "yellow";
}
numbers.onblur = function(event) {
event = event || window.event;
var target = event.target || event.srcELement;
if (/[^\d]/.test(target.value)) {
target.style.backgroundColor = "red";
} else {
target.style.backgroundColor = "";
}
}
numbers.onchange = function(event) {
event = event || window.event;
var target = event.target || event.srcELement;
if (/[^\d]/.test(target.value)) {
target.style.backgroundColor = "red";
} else {
target.style.backgroundColor = "";
}
}
</script>
</html>
在上面代码中,onfocus事件处理程序将文本框的背景颜色修改为黄色,以清楚地表示当前字段已经激活。onblur和onchange事件处理程序则会发现非数值字符时,将文本框背景颜色修改为红色。为了测试用户输入的是不是非数值,这里针对文本框的value属性使用了简单的正则表达式。而且,为了确保无论文本框的值如何变化,验证规则始终如一,onblur和onchange事件处理程序中使用了相同的正则表达式。
关于blur和change事件发生顺序并没有严格的规定,不同的浏览器没有统一的规定。因此,不能假定这两个事件总会以某种顺序依次触发。
提交表单
使用<input>
或<button>
标签都可以定义提交按钮,只要将type属性值设置为”submit“即可,而图像按钮则是通过<input>
的type属性值设置为”image“。当单击提交按钮或图像按钮时,就会提交表单。submit事件类型仅在单击提交按钮,或者在文本框中输入文本时按Enter键触发。
- 【实例1】在下面实例中,当在表单内的文本框中输入文本之后,单击”提交“按钮会触发submit事件,该函数将禁用表单提交数据,而是弹出提示对话框显示输入的文本信息。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<form action="" id="form1" name="form1" method="POST">
<input type="text" name="t" id="t">
<input type="submit" name="">
</form>
</body>
<script>
var t = document.getElementsByTagName("input")[0];
var f = document.getElementsByTagName("form")[0];
f.onsubmit = function(e) {
alert(t.value);
return false;
}
</script>
</html>
- 【实例2】在下面实例中,当表单没有包含包含”提交“按钮时,在文本框中输入文本之后按Enter键也一样能触发submit事件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<form action="" id="form1" name="form1" method="POST">
<input type="text" name="t" id="t">
<!-- <input type="submit" name=""> -->
</form>
</body>
<script>
var t = document.getElementsByTagName("input")[0];
var f = document.getElementsByTagName("form")[0];
f.onsubmit = function(e) {
alert(t.value);
return false;
}
</script>
</html>
- 注意:在
<textarea>
文本区中按Enter键只会换行,不会提交表单。
以这种方式提交表单时,浏览器会在请求发送给服务器之前触发submit事件,用户有机会验证表单中的数据,并决定是否允许表单提交。
- 【实例3】阻止事件的默认行为可以取消表单提交。下面实例先验证文本框中是否输入字符,如果为空,则调用preventDefault()方法阻止表单的提交。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<form action="" id="form1" name="form1" method="POST">
<input type="text" name="t" id="t">
<!-- <input type="submit" name=""> -->
</form>
</body>
<script>
var t = document.getElementsByTagName("input")[0];
var f = document.getElementsByTagName("form")[0];
f.onsubmit = function(e) {
if (t.value.length < 1) {
var event = e || window.event;
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
}
}
</script>
</html>
- 【实例4】如果要禁止按Enter键提交响应,可以检测键盘响应,当按下Enter键时设置其返回值为false,从而取消键盘的默认动作,禁止按Enter键提交响应行为。
var t = document.getElementsByTagName("input")[0];
t.onkeypress = function(e) {
var e = e || window.event;
return e.keyCode != 13; //当按下Enter键时返回false,禁止默认键盘行为
}
- 【实例5】调用submit()方法也可以提交表单,这样就不需要表单包含”提交“按钮,任何时候都可以正常提交表单。
var t = document.getElementsByTagName("input")[0];
var f = docuemnt.getElementsByTagName("form")[0];
t.onchange = function() {
f.submit(); // 提交表单
}
- 注意:调用submit()方法不会触发submit事件,因此在调用此方法之前要先验证表单数据。
- 提示:在实际应用中,会出现用户重发提交表单现象。例如,在第1次提交表单后,如果长时间没有反应,用户可能会反复点击提交按钮,这样容易带来严重的后果,服务器反复处理请求组,或者取消保存用户多次提交的订单。解决方法:在第一次提交表单后禁用提交按钮,或者在onsubmit事件处理函数中取消表单提交操作。
重置表单
为<input>
和<button>
标签设置type=“reset”属性可以定义重置按钮。
<input type="reset" value="重置按钮">
<button type="reset">重置按钮</button>
- 【实例1】下面实例设计当单击【重置】按钮时,弹出提示框,显示文本框中的输入值,同时恢复文本框的默认值,如果没有默认值,则显示为空。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<form action="" id="form1" name="form1" method="POST">
<input type="text" name="t" id="t">
<input type="reset" name="">
</form>
</body>
<script>
var t = document.getElementsByTagName("input")[0];
var f = docuemnt.getElementsByTagName("form")[0];
t.onreset = function(e) {
alert(t.value);
}
</script>
</html>
- 【实例2】也可以利用这个机会,在必要时取消重置操作。下面实例检测文本框中的值,如果输入10个字符以上,就不允许重置了,避免丢失输入的文本。
var t = document.getElementsByTagName("input")[0];
var f = docuemnt.getElementsByTagName("form")[0];
t.onreset = function(e) {
if (t.value.length > 10) {
var event = e || window.event;
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
}
}
- 提示:用户也可以使用form.reset()方法重置表单,这样就不需要包含重置按钮。