事件
事件:用户与浏览器之间特定的交互瞬间。
事件类型
web浏览器发生的事件有很多类型,不同的类型有着不同的信息。"DOM3级事件"包含有:UI事件、焦点事件、滚轮事件、文本事件、鼠标事件、键盘事件、合成事件、变动事件、变动名称事件等。
UI事件
UI事件指的是那些
不一定与用户操作有关 的事件。DOM规范中留下向后兼容。UI事件包含:
- load:当页面加载后在window上面触发,当所有框架加载完成后在框架上触发,当图像加载完成后在<img>元素上面触发。
- unload:当页面卸载后在window上面触发。
- abort:当用户停止下载过程时,如果嵌入的内容没有加载完,则在<object>元素上触发。
- error:当发生JavaScript错误时在window上面触发。
- select:当用户选择文本框(input或textarea)或一个字符串时触发。
- resize:当窗口或框架大小变化时在window上面触发。
- scroll:当用户滚动滚动条的元素中的内容时,在元素上触发。
这些事件多数与window对象有关。
load事件
JavaScript中最常用的就是load。当页面加载完成时(图像加载完成、JavaScript外部资源加载完成、css外部资源加载完成)在window上面触发。定义load事件有两种方法:
第一种就是用JavaScript定义:
EventUtil.addHandler(window, "load", function (event) {
alert("load");
}); //load事件
根据前面所定义的对象EventUtil,调用其属性可以添加事件。
第二种方法就是在HTML的<body>中定义:
<body load="alert("load");">
//Html代码
</body>
建议尽可能使用JavaScript代码来定义load事件。
图像上面也可以加载load事件,除了可以在HTML的<img>中定义外,还可以用JavaScript定义,建议用JavaScript来定义load事件。
var images = document.getElementById("imgs");
EventUtil.addHandler(images, "load", function (event) {
event = EventUtil.getEvent(event);
alert(EventUtil.getTarget(event).src);
});
通过JavaScript来添加onload事件处理程序,并传入event对象,再通过src来访问<img>的信息。
在创建新的<img>元素时,可以为其指定一个事件处理程序,以便图像加载完成后弹出提示。
注意:要在指定src属性之前先指定事件。
//当页面加载完成后,再向页面创建新元素对象。
EventUtil.addHandler(window, "load", function (event) {
//创建一个新的元素对象
var image = document.createElement("img");
//当创建的img元素加载完成后。
EventUtil.addHandler(image, "load", function (event) {
event = EventUtil.getEvent(event);
alert(EventUtil.getTarget(event).src); //得到新创建的Img元素的信息
});
document.body.appendChild(image); //将这个新创建的元素对象<img>添加到body后面,即页面上。
image.src = "smile.gif"; //在指定src属性之前,先指定事件。
});
在这个例子中,我们先为window对象定义一个onload事件处理程序,因为我们想向页面中添加一个新元素,必须等页面加载完成后才能实现,如果在加载完成之前就操作document.body会报错的。然后,再添加一个新元素并设置了onload事件处理程序,最后将这个新的元素添加到页面中,并为其设置src属性。
注意:新元素不一定要从添加到文档后才开始下载,只要设置了src属性就会开始下载。
除了以上方法外,还可以使用
DOM 0级的Image()对象创建图像元素。
window.onloag = function () {
var img = new Image(); //创建一个图像实例
img.onload = function () {
console.log("图像加载完成");
};
img.src = "smile.gif"; //为该图像设置src属性
};
unload事件
只要文档被卸载后就会触发,当用户从一个页面切换到另一个页面就会触发,一般用于清除引用,避免内存泄露使用。定义unload事件也有两种方式,与定义load事件一样,这里就不一一列举了。
EventUtil.addHandler(window, "unload", function (event) {
alert("unload");
}); /resize事件
resize事件
resize事件是当窗口或框架的尺寸大小发生变化时触发,这个事件是在window上触发的。我们还是建议使用JavaScript定义on
resize事件处理程序。也有两种定义方法。
EventUtil.addHandler(window, "resize", function (event) {
alert("resize");
}); /resize事件
该事件会在窗口大小不断变化时重复触发,因此建议代码简单点。
scroll事件
定义方法与load、unload、resize一样,也是两种即:在HTML中定义或用JavaScript定义,我们建议用JavaScript定义。
scroll是在window对象上发生的,但它实际上是反应了相应元素的变化。在混杂模式下,是反应<body>的scrollLeft、scrollTop的变化。而在标准模式下,除了欧朋之外的浏览器是反应<html>的scrollLeft、scrollTop的变化。因为在写代码时,建议判断当前浏览器是哪个模式。如:
window.onscroll = function () {
if (document.compatMode == "CSS1Compat") { //标准模式下,是<html>
console.log(document.documentElement.scrollTop);
} else { //混杂模式下,是<body>
console.log(document.body.scrollTop);
}
};
Document类访问子节点的方式:
- document.documentElement
- childNodes
- document.body
注:scroll事件在文档被滚动期间会重复触发,因此建议代码简单点。
焦点事件
焦点会在页面得到焦点或失去焦点时触发。
- focus,在得到焦点的元素上触发,这个事件不会冒泡。
- focusIn,在得到焦点的元素上触发 ,这个事件会冒泡。
- DOMFocusIn,在得到焦点的元素上触发,这个事件会冒泡。
- DOMFocusOut,在失去焦点的元素上触发。
- blur,在失去焦点的元素上触发,这个事件不会冒泡。
- focusout,在失去焦点的元素上触发,这个事件会冒泡。
例如:当input元素获取焦点时,会触发focus事件。
var input1 = document.getElementById("input1");
input1.onfocus = function (event) {
alert("hi"); //hi
};
当input元素失去焦点时,会触发blur事件。
var input1 = document.getElementById("input1");
input1.onblur = function (event) {
alert("失去焦点"); //失去焦点
};
鼠标与滚轮事件
常见的鼠标事件有9种:
- click:鼠标单击事件,当单击鼠标(一般为左键)或按下回车键时,会触发事件。
- dbclick:鼠标双击事件,当双击鼠标时,会触发事件。
- mousedown:当任意按下鼠标键时,会触发事件。
- mouseup:当释放鼠标铵键时,会触发事件。
- mouseover:当鼠标移动进到当前元素的区域就会触发事件。
- mouseout:当鼠标移出当前元素的区域就会触发事件。
- mousemove:当鼠标在当前元素区域内不断移动时,会重复触发事件。
事件触发顺序:
1、mousedown
2、mouseup
3、click
4、mousedown
5、mouseup
6、click
7、dbclick
当按下鼠标按键时:
var input1 = document.getElementById("input1");
input1.onmousedown = function (event) {
alert("按下鼠标按键");
};
当释放鼠标按键时:
var input1 = document.getElementById("input1");
input1.onmouseup = function (event) {
alert("释放鼠标按键");
};
当单击鼠标按键时:
var input1 = document.getElementById("input1");
input1.onclick = function (event) {
alert("点击鼠标按键");
};
当双击鼠标按键时:
var input1 = document.getElementById("input1");
input1.ondbclick = function (event) {
alert("双击鼠标按键");
};
客户区坐标位置
鼠标事件都是在浏览器视口中特定位置发生的,这些位置信息保存在对象的
clientX和clientY属性中,这两个属性分别表示鼠标在
视口中水平位置和垂直位置。
注:这两个值不包括页面滚动的距离,也就是说,这两个值
不包括鼠标在页面中的位置,只是表示
在视口中的某位置发生了事件。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript</title>
</head>
<body>
<input id="input1" type="button" value="单击事件">
<script>
/* 在此处书写javascript代码 */
//客户区坐标,不包括页面滚动的距离
var input1 = document.getElementById("input1");
input1.onclick = function (event) {
alert("clientX:" + event.clientX + " clientY:" + event.clientY);
};
</script>
</body>
</html>
效果:
点击按钮会弹出警告框,分别表示
事件发生时鼠标指针在
视口中的位置。注:这些值中不包括页面滚动的距离,也就是说表示的值不是鼠标在页面中的位置,仅表示在视口中的位置。
页面坐标位置
客户区坐标位置只是表示鼠标在视口的某位置发生了事件,而想要表示
鼠标在页面中的某个位置发生了事件,则用
pageX和
pageY表示鼠标在页面中的水平位置和垂直位置。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript</title>
</head>
<body>
<input id="input1" type="button" value="单击事件">
<script>
/* 在此处书写javascript代码 */
var input1 = document.getElementById("input1");
//页面坐标位置,包括了页面滚动的距离
input1.onclick = function (event) {
alert("pageX:" + event.pageX + " pageY:" + event.pageY);
};
</script>
</body>
</html>
视口位置与页面位置的区别:
视口位置不包括页面滚动的距离,也就是说当页面出现有滚动条时,即使在视口的同一位置点击相同的元素,视口位置与页面位置所返回的值是不同的。
视口位置是从视口区的顶端即最后一工具栏下和浏览器左端开始计算的,即使水平方向和垂直方向上出现了滚动条,也是从视口的顶端和浏览器的左边作为起始坐标计算的。
而页面位置则从页面的最顶端和页面的最左边开始计算的,即使有了滚动条。
这是视口位置:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript</title>
</head>
<body>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input id="input1" type="button" value="单击事件">
<script>
/* 在此处书写javascript代码 */
var input1 = document.getElementById("input1");
input1.onclick = function (event) {
alert("clientX:" + event.clientX + " clientY:" + event.clientY);
};
</script>
</body>
</html>
这里没有包括滚动条的距离。
页面位置:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript</title>
</head>
<body>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input id="input1" type="button" value="单击事件">
<script>
/* 在此处书写javascript代码 */
var input1 = document.getElementById("input1");
//页面坐标位置,包括了页面滚动的距离
input1.onclick = function (event) {
alert("pageX:" + event.pageX + " pageY:" + event.pageY);
};
</script>
</body>
</html>
效果:
这里包括了滚动条的距离。
从上可以看出,当没有滚动条时,视口位置与页面位置有着相同的值。而当有了滚动条后,如果水平方向有滚动条,那么clientX与pageX的值不同,同理,垂直方向亦一样。当水平、垂直方向上都有滚动条时,那么clientX与pageX,clientY与pageY的值均不同。
屏幕坐标位置
鼠标除了有相对于浏览器窗口的位置,还有相对于屏幕的位置,即
screenX与screenY。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript</title>
</head>
<body>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input type="button"><br>
<input id="input1" type="button" value="单击事件">
<script>
/* 在此处书写javascript代码 */
var input1 = document.getElementById("input1");
//屏幕坐标
input1.onclick = function (event) {
alert("screenX:" + event.screenX + " screenY:" + event.screenY);
};
</script>
</body>
</html>
效果:
从视口位置例子与屏幕位置例子可以看出,即使鼠标在同一点击事件,这两个例子中的clientY与screenY的值不同的,screenY的值大一些,这是因为浏览器的菜单栏与工具栏要占一定的空间。
以上的例子均是在全屏模式下比较的,缩小浏览器窗口也是这样的道理。
修改键
鼠标事件主要是由鼠标触发的,但有时有些按键也会影响到鼠标事件的操作,这些键叫做 修改键。修改键有:
Shift、Ctrl、Alt和Meta(windows下是Windows键,苹果下是Cmd键),DOM为此定义了四个属性,表示这四个键的状态:
shiftKey、CtrlKey、altKey和metaKey。
如果在鼠标触发事件的同时,也按下了这四个修改中的其中一个或多个,其状态属性返回true。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript</title>
</head>
<body>
<input id="input1" type="button" value="单击事件">
<script>
/* 在此处书写javascript代码 */
var input1 = document.getElementById("input1");
input1.onclick = function (event) {
alert("修改键");
//定义一个Array类,用于保存用户触发了的修改键。
var keys = new Array();
//判断在按下鼠标键的同时,是否也按下了其它的修改键,如果按下了,将相应修改键的名称推入数组。
if (event.shiftKey) {
keys.push("shifKey");
}
if (event.ctrlKey) {
keys.push("ctrl");
}
if (event.altKey) {
keys.push("altKey");
}
//最后将数组中的值用join()方法以字符串的形式用逗号隔开。
alert("keys:" + keys.join(","));
};
</script>
</body>
</html>
效果:
例子中,在触发鼠标事件的同时,也按下了shift和ctrl按键,并返回了修改键相应的名称。
鼠标的按钮
在鼠标事件中,有mousedown和mouseup两个事件,分别表示鼠标键被按下和鼠标键被释放。这两个事件的event对象有一个叫botton的属性,该属性记录了
触发mousedown和mouseup事件时,用户所按下的鼠标的按键状态。
我们知道,鼠标主要有三个按键,分别是
主按键、中间按键、次按键。botton属性所记录的就是这三个按键的状态。
在DOM的botton属性中,当botton
1、返回0时,表示用户按下的是鼠标的主按键。
2、返回1时,表示用户按下的是鼠标的中间按键(也就滑轮)。
3、返回2时,表示用户按下的是鼠标的次按键。
注:鼠标默认的按键是最左边的为主按键,中间的滑轮为中间按键,最右边的为次按键,当然,用户可以自定义设置这三个按键。
<!doctype html>
<html lang="zh">
<head>
<meta charset="utf-8">
<title>JavaScript</title>
</head>
<body>
<input id="input1" type="button" value="单击事件">
<script>
/* 在此处书写javascript代码 */
var input1 = document.getElementById("input1");
input1.onmousedown = function (event) {
console.log("button属性");
//定义一个Array类,用于保存用户触发了的修改键。
var keys = new Array();
//判断在按下鼠标键的同时,是否也按下了其它的修改键,如果按下了,将相应
修改键的名称推入数组。
if (event.shiftKey) {
keys.push("shif");
}
if (event.ctrlKey) {
keys.push("ctrl");
}
if (event.altKey) {
keys.push("alt");
}
//最后将数组中的值用join()方法以字符串的形式用逗号隔开。
console.log("keys:" + keys.join(","));
switch (event.button) {
case 0:
console.log("用户按下鼠标的主按键");
break;
case 1:
console.log("用户按下鼠标的中间按键");
break;
case 2:
console.log("用户按下鼠标的次按键");
break;
}
};
</script>
</body>
</html>
效果:
鼠标datail属性
在"DOM2级事件"中Event对象还提供了一个叫detail的属性,该属性表示事件的更多信息。比如:
鼠标事件中,该属性包含一个数值,表示发生了多少次单击,
在同一个元素上,连续发生一次mousedown和一次mouseup算作一次单击,detail的值是从1开始计数,每次单击发生后数值递增。如果鼠标在mousedown和mouseup之间移动了位置,则datail重置为0。
注:如果是连续地单击鼠标,detail值会递增并显示,表示此次单击了多次,但如果是间断地单击鼠标,则datail的值还是1,表示为此次只单击了一次。
<body>
<input id="inpt1" type="button" value="单击事件">
<script>
var inpt1 = document.getElementById("inpt1");
//鼠标单击事件,datail记录单击的次数。
inpt1.onclick = function (e) {
console.log(e.detail);
};
</script>
<script src="" id="qq"></script>
</body>
效果:
可以看出,连续单击鼠标,detail值会递增,如果是间断地单击鼠标,则detail值还是1,只会重叠。
鼠标滑动事件
当用户通过鼠标滑轮(滚轮)与页面交互、上下滚动页面时,会触发一个叫
mousewheel的事件即鼠标滑动事件。该事件的event对象不仅包含了鼠标事件的所有信息,还包含一个叫做wheelDelta属性,当鼠标滑轮滚动时,该属性返回120的倍数。当向前滑动时(即页面向下滑动),wheelDelta属性返回-120的倍数,当向后滑动时(即页面向上滑动),wheelDelta属性返回+120的倍数。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript</title>
</head>
<body>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input ><br>
<input id="input1" type="button" value="单击事件">
<script>
/* 在此处书写javascript代码 */
var input1 = document.getElementById("input1");
//当触发mousewheel事件时,wheelDelta属性记录了滑动数据
document.onmousewheel = function (event) {
if (event.wheelDelta > 0) {
console.log("鼠标向前滑动");
} else if (event.wheelDelta < 0) {
console.log("鼠标身后滑动");
} else {
console.log("未滑动");
}
console.log(event.wheelDelta);
};
</script>
</body>
</html>
效果:
键盘与文本事件
用户在使用键盘时会触发键盘事件。常用的键盘事件有3种:
1、keydown:按下键盘上的任意按键会触发事件,如果按住按键不放,则会重复触发事件。
2、keyup:当释放键盘按键时会触发事件。
3、keypress:当用户按住键盘上的字符键时会触发事件,如果按住不放,则会重复触发事件。
注:当用户按了一下字符键时,首先会触发keydown事件,接着会触发keypress事件,最后会触发keyup事件。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript</title>
</head>
<body>
<input id="input1" type="button" value="单击事件">
<script>
/* 在此处书写javascript代码 */
var input1 = document.getElementById("input1");
//当按下键盘按键时会触发。
document.onkeydown = function (event) {
console.log("您按下了按键");
};
//当按下的是字符键时会触发
document.onkeypress = function (event) {
console.log("您按下的是字符键");
};
//释放按键时会触发
document.onkeyup = function (event) {
console.log("您释放了按键");
};
</script>
</body>
</html>
效果:
注:键盘事件与鼠标事件一样都支持修改键即:shiftKey、ctrlKey、altKey、metaKey等。
键码
当触发keydown和keyup事件时,其event对象有个叫做
keyCode的属性,其包含了用户所按下的按键的字符键码。例如:字符“q”对应的键码为81,字符"w"对应的键码是87。
注:keyCode属性不会区分字符大小写状态的,例如:不管是大写A还是小写a均返回65。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript</title>
</head>
<body>
<input id="input1" type="button" value="单击事件">
<script>
/* 在此处书写javascript代码 */
var input1 = document.getElementById("input1");
document.onkeydown = function (event) {
console.log(event.keyCode);
};
document.onkeyup = function (event) {
console.log(event.keyCode);
};
</script>
</body>
</html>
效果:
其中,116对应的按键是F5键即刷新键。之所以显示再次编码,是因为触发和keydown和keyup事件。
常见ASCII表如下:
字符编码
当触发keypress事件时,就意味着会影响屏幕中文本的显示(意味着会插入字符或者删除字符)。当触发keypress事件时,其event对象有个叫做charCode的属性,其属性包含的是用户所按按键的字符编码,与keydown与keyup的even对象的keyCode属性相似。例如:当用户按下"a"时,该属性返回97,当按下"A",该属性返回65。
注:charCode与keyCode的区别在于:
keyCode不会区分字符的大小写状态,也就是说不管用户所按下的是小写的“a”,还是大写的"A",keyCode都是返回的 65。
而charCode会区分大小写状态,小写“a”返回97,大写“A”返回65。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript</title>
</head>
<body>
<input id="input1" type="button" value="单击事件">
<script>
/* 在此处书写javascript代码 */
var input1 = document.getElementById("input1");
//keypress事件的event对象的charCode属性
document.onkeypress = function (event) {
console.log(event.charCode);
};
</script>
</body>
</html>
效果:
分别按下的是:a、A、b、B。
DOM3级变化
DOM3级中,新增了两个属性:key和char,这两个属性取代了charCode属性。
key属性返回的是一个字符串,即用当用户所按键是字符时,会返回相应的字符,如"k"、“w”等,而当用户所按为非字符按键时,该属性会返回相应的键名,如“shift”,"ctrl"等。
char属性与key属性相似,当用户按下字符按键时,会返回相应的字符,但,当用户按下的是非字符按键时,该属性会返回null。
由于存在跨浏览器问题,还是不建议使用char和key属性。
DOM3中的
location属性,该属性返回一个数值,表示用户所按下的按键处于键盘的
什么位置。返回0表示在默认键盘位置,返回1表示在左侧位置(即左侧的shift),返回2表示 在右侧位置(即右侧的shift),返回3表示数字小键盘,返回4表示移动设备键盘,返回5表示手柄。火狐和谷歌支持的是
keyLocaltion属性。
textInput事件
当用户在可编辑区域输入字符时,会触发该事件。
textInput事件与keypress事件的区别:
1、textInput事件只有在可输入区域才能触发,而keypress事件就是只要任何获取焦点的元素就会触发该事件。
2.、只有输入
实际的字符才能触发textInput事件,而keypress事件,只要按下是否能影响文本显示的按键时就能触发。
textInput事件考虑的是字符,因为该事件的Event对象只有一个
data属性,该属性包含的值就是用户输入的字符,包括字符的大小写形式。
<body>
<input id="text1" type="text" >
<script>
var text1 = document.querySelector("#text1");
text1.ontextInput = function (e) {
alert(e.date);
};
</script>
</body>
设备中的按键事件
例如一些遥控器等设备。
复合事件
复合事件是DOM3新增的一类事件,用于处理输入的IME的输入序列。
复合事件可以让用户输入物理键盘上没有的字符。
变动事件
变动事件:DOM中某一部分发生变化时就会触发。如删除节点、插入节点等操作。DOM2级中的变动事件如下:
- DOMSubtreeModified:在DOM结构中发生任何变化时触发。这个事件在其它事件触发后都会触发。
- DOMNodeRemoved:在节点从其父节点中移出时触发。(删除节点时)
- DOMNodeInserted:在一个节点作为另一个节点的子节点插入时触发。(插入节点)
- DOMNodeInsertedIntoDocument:在一个节点直接被插入到文档中或通过DOM子树结构插入到文档中时触发。
- DOMNodeRemovedFromDocument:在一个节点直接从文档中移出或通过DOM子树结构移出时触发。
删除节点
可以使用
removeChild()或
replaceChild()方法来删除节点,在删除节点的过程中,会触发以下事件:
- 第一步,首先会触发DOMNodeRemoved(删除节点时会触发)事件,该事件的目标(event.target)是被删除的节点,而event.relatedNode属性包含着对目标节点的父节点的引用。在触发该事件之时,节点还未被删除,此时parentNode属性仍然是其父节点(与event.relateNode引用的一样,该节点还未被删除,肯定有其父节点)。这个事件会冒泡,因此可以在DOM结构的任何层次上处理(也就是说,可以在DOM结构的任何层次上创建该事件的处理程序)。
- 如果被删除的节点包含子节点(被删除的节点有子节点),就会在其所有子节点上以及该节点上相继触发DOMNodeRemovedFromDocument事件,该事件不会冒泡,所以只能指定给其中一个子节点的事件处理程序才会触发(也就是说只能于被删除的节点以及子节点创建处理程序)。这个事件的目标(event.target)是相应的子节点或被移出的这个节点。除此之外event对象不包含其它信息。
- 最后会触发DOMSubtreeModifined事件,这个事件引用的是被删除节点的父节点。除此之外event对象不包含任何其它事件信息。
- 经过以上步骤后,节点从文档中被删除(ElementNode.parent.removeChild(ElementNode))。
举例说明:
<!doctype html>
<html lang="zh-en">
<head>
<meta charset="utf-8">
<title>变动事件之删除节点操作</title>
<style>
</style>
</head>
<body>
<ul id="myList">
<li>li 1</li>
<li>li 2</li>
<li>li 3</li>
<li>li 4</li>
</ul>
<script>
/*在页面加载完成之后再执行操作。
注:以下是针对兼容DOM的浏览器操作方法,如果是针对IE或其它浏览器,可用跨浏览器的方法
*/
window.onload = function (e) {
//通过ID获取ul元素的引用
var list = document.querySelector("#myList");
//首先是触发DOMNodeRemoved事件,event.relateNode包含对其父节点的引用(即document.body),由document添加该事件处理程序也可以。
list.addEventListener("DOMNodeRemoved", function (e) {
console.log(e.type); //DOMNodeRemoved
console.log(e.target); // <ul>...</ul>
console.log(e.relateNode); //undefined
console.log(list.parentNode); //<body>...</body>
});
//接着在被删除节点上触发DOMNodeRemovedFromDocument事件
list.addEventListener("DOMNodeRemovedFromDocument", function (e) {
console.log(e.type); //DOMNodeRemovedFromDocument
console.log(e.target); //<ul>...</ul>
});
//再接着在被删除节点的子节点上触发DOMNodeRemovedFromDocument事件
list.firstChild.addEventListener("DOMNodeRemovedFromDocument", function (e){
console.log(e.type); //DOMNodeRemoveFromDocument
console.log(e.target); //#text 因为<li>包含的是文本内容
});
/*随之触发DOMSubtreeModifined事件,该事件的目标是被删除节点的父节点(即document.body)
此时Event对象不会包含任何有关事件的信息,所以以下的内容不会返回。
*/
list.addEventListener("DOMSubtreeModified", function (e) {
console.log(e.type);
console.log(e.target);
});
//设置以上事件处理程序之后,该元素从其父节点中被删除。
list.parentNode.removeChild(list);
/*
该方式也行,因为在这个例子中,<ul>元素的父节点就是<body>
document.body.removeChild(list);
*/
}
</script>
</body>
</html>
效果:
可以看出当要删除<ul>节点时会经过以下的操作步骤:
1、首先在<ul>元素上触发DOMNodeRemoved事件,该事件的目标就是当前元素节点即<ul>,该事件的Event对象的relatedNode引用的是其父节点即document.body
2、接着,在<ul>元素上触发DOMNodeRemovedFromDocument事件,该事件的目标就是<ul>元素本身,并且Event对象不包含其它信息了。
3、再接着,在<ul>元素的子节点(当然要看被删除节点是否有子节点,如果没有,该行当没说。)<li>元素上也触发DOMNodeRemovedFromDocument事件,这次该事件的目标就是"#text",因为<li>元素包含的是文本内容。
4、随着在其父节点上(document.body)上触发DOMSubtreeModified事件,该事件的目标就是document.body。
5、最后,经过以上事件处理程序的操作,将<ul>元素节点从其父元素中删除。
注:如果将节点从其父节点中删除的操作(list.parentNode.removeChild(list))放于以上事件之前,那么以上事件就没有效果。因为,节点已经删除也再执行些操作已经没有用了。
插入节点
在使用appendChild()、insertBefore()、replaceChild()方法来插入节点,在执行这些操作时,会触发以下事件:
- 第一步,首先会触发DOMNodeInsered事件,该事件的目标是被插入的节点(event.target),而event.relatedNode包含一个父节点的引用。在这个事件触发时,该节点已经被插入到文档中了。这个事件有冒泡,所有可以DOM的任何层次上处理(也就是说,可以在DOM结构的任何层次上创建该事件的处理程序)。
- 第二步,接着会在新插入的节点上触发DOMNoeInseredIntoDocument事件。该事件不会冒泡,所有需在该节点被插入之前为它添加事件处理程序(也就是说只能新插入的节点上创建处理程序),该事件的目标就是这个新插入的节点,除此之外Event对象不包含其它事件信息。
- 第三步,最后在新插入的节点的父节点上触发DOMSubtreeModefied事件,该事件不包含任何有关事件的信息。
- 最后,经过以上事件处理程序之后,在某个节点下插入新的节点操作。
就以上面的例子为基础,为<ul>元素节点新插入一个子节点。注:该新节点需要新创建。
<!doctype html>
<html lang="zh-en">
<head>
<meta charset="utf-8">
<title>变动事件之删除节点操作</title>
<style>
</style>
</head>
<body>
<ul id="myList">
<li>li 1</li>
<li>li 2</li>
<li>li 3</li>
<li>li 4</li>
</ul>
<script>
/*在页面加载完成之后再执行操作。
注:以下是针对兼容DOM的浏览器操作方法,如果是针对IE或其它浏览器,可用跨浏览器的方法
*/
window.onload = function (e) {
//通过ID获取ul元素的引用
var list = document.querySelector("#myList");
//创建一个新子节点,并添加内容。
var item = document.createElement("li");
item.innerHTML = "li 5";
//首先是触发DOMNodeInserted事件,event.relateNode包含对一个父节点的引用(即<ul>)
item.addEventListener("DOMNodeInserted", function (e) {
console.log(e.type); //DOMNodeInserted
console.log(e.target); // <li>...</li>
console.log(e.relateNode); //undefined
console.log(list.parentNode); //<body>...</body> 在文档中创建的节点,开始时其父节点为<body>
});
//接着在新节点上触发DOMNodeInsertedIntoDocument事件
item.addEventListener("DOMNodeInsertedIntoDocument", function (e) {
console.log(e.type); //DOMNodeInsertedIntoDocument
console.log(e.target); //<li>...</li>
});
/*随之触发DOMSubtreeModifined事件,该事件的目标是新插入节点的父节点(即<ul>)
此时Event对象不会包含任何有关事件的信息,所以以下的内容不会返回。
*/
document.addEventListener("DOMSubtreeModified", function (e) {
console.log(e.type);
console.log(e.target);
});
//设置以上事件处理程序之后,将新节点插入到文档中(即父节点中)。
list.appendChild(item);
//新节点插入到某个节点中,其父节点为某个节点。
console.log(item.parentNode); // <ul>...</ul>
}
</script>
</body>
</html>
效果:
要插入新的节点,需要在插入之前创建这个节点。在插入之前为将要触发的事件创建处理程序,以显示事件的信息
个人提示:我们为某个事件添加事件处理程序的目的主要是获取该事件的一切信息,如果添加事件处理程序,事件照样执行,但事件的信息不会显示出来,需要为其事件添加处理程序才能看到有关事件的信息。
HTML5事件
DOM规范没有涵盖浏览器支持的所有事件,HTML5列出了浏览器的支持的所有事件,下面将介绍得到浏览器完美支持的事件
contextmenu事件
默认的上下文菜单栏:当点击鼠标右键时,会出现一个默认的菜单栏。为了实现自定义的上下文菜单,开发人员遇见的主要问题是:如何确定要显示的菜单,如果隐藏和操作菜单。于是contextmenu事件出现了。
contextmenu事件属于鼠标事件,一般为鼠标右键事件,它是冒泡的,所以可以为document指定一个事件处理程序。该事件的目标是被用户操作的元素。
那么为实现了自定义的上下文菜单,首先是
阻止鼠标右键的默认行为(即点击鼠标右键弹出默认菜单栏)。contextmenu事件属于鼠标事件,那么就可以通过event对象得到鼠标的位置,恰好自定义菜单出现的位置也是鼠标单击的位置。
通常使用contextmenu事件来显示自定义的菜单栏,而通过鼠标的click事件来隐藏该菜单栏。
比如:通过按鼠标右键弹出自定义菜单栏来选择上下面、首页、尾页等操作:
<!doctype html>
<html lang="zh-en">
<head>
<meta charset="utf-8">
<title>contextmenu事件</title>
<style>
#myDiv {
width: 200px;
height: 100px;
border: 1px solid blue;
}
#myMenu {
position: absolute;
visibility: hidden;
width: 185px;
height: 25px;
background-color: silver;
}
#myMenu li {
float: left;
list-style: none;
}
</style>
</head>
<body>
<div id="myDiv">文章内容</div>
<ul id="myMenu">
<li>首页</li>
<li>上一页</li>
<li>下一页</li>
<li>尾页</li>
</ul>
<script>
window.onload = function (e) {
var div = document.querySelector("#myDiv");
var menu = document.querySelector("#myMenu");
//添加contextmenu事件处理程序,自定义鼠标右键的上下文菜单
div.addEventListener("contextmenu", function (e) {
//阻止鼠标右键的默认行为(按鼠标右键有默认的菜单栏)
e.preventDefault();
//上下文菜单栏会出现在鼠标点击的位置
menu.style.left = e.clientX + "px";
menu.style.top = e.clientY + "px";
//点击鼠标显示菜单栏
menu.style.visibility = "visible";
});
//单击鼠标左键,隐藏自定义菜单栏。
document.addEventListener("click", function (e) {
menu.style.visibility = "hidden";
});
};
</script>
</body>
</html>
效果:
从上述例子可以看出,当在<div>外面点击鼠标右键时,会弹出默认的菜单栏,在<div>里面点击鼠标右键时,阻止了默认的上下文菜单栏,会弹出自定义的菜单栏。当点击鼠标左键时,会隐藏菜单栏。
beforeunload事件
当卸载页面、或者重新刷新页面时,可能我们没有保存数据,刷新之后,数据就会消失。如果给winsow添加一个叫beforeunload()的事件处理程序,那么当我们要重新刷新页面时,页面会弹出警告框,要我们确认是否要刷新这个页面,这是一个友好的提示:
window.onbeforeunload = function (e) {
var message = "确定要离开页面吗";
return message;
};
效果:
DOMContentLoaded事件
window的load事件会在页面加载完成之后触发,但这个过程可能会因为要加载的资源大多而等的时间较长。DOMContentLoaded事件在形成完整的DOM结构之后就会触发,而不必等到图像、JavaScript资源、CSS资源加载完毕之后才触发。这样用户就可以早点与浏览器交互。
可以为document或window添加处理程序,但目标还是document。
window.addEventListenter("DOMContentLoaded", function () {
alert("用户早点与浏览器交互");
});
readystatechange事件
该事件的目的是提供
与文档或元素加载状态有关的信息。readystatechange事件的Event对象有个readyState属性,保存着状态值。状态值有5个:
1、uninitialized(未初始化):对象存在但未初始化。
2、loading:对象正在加载数据。
3、loaded:对象已经加载完数据。
4、interactive:可以操作对象了,但未完全加载。
5、compelete:对象已经加载完毕。
pageshow事件和pagehide事件
注:这两个事件的目标是document,但必需添加到window对象上。
浏览器有一个特性叫做"往返缓存",
往返缓存(bfcache)可以在用户使用浏览器的"后退"和"前进"按钮时加快页面的转换速度。bfcache中不仅保存了页面的数据,还保存了DOM和JavaScript的状态。将整个页面保存在了内存中,如果页面是在bfcache中,那么打开这个页面时,不会触发load事件。
pageshow事件会在页面显示时触发,无论该页面是在bfcahce中,还是触发了load事件。
pageshow事件会在load事件触发之后触发。
pageshow事件的Event对象中有个
叫persisted的属性,该属性是一个布尔值,true表示页面被保存在bfcache中,如果返回false,则表示页面是重新加载的。
与pageshow事件相对的就是
pagehide事件,该事件是
在unload事件之后触发的,同样Event对象中有个persisted属性,用途有点不同。
如果返回true,表示页面卸载之后被保存在bfcache中。
hashchange事件
HTML5新增了一个hashchange事件,该事件反应了URL变化的信息和状态。Event对象中有两个属性:oldURL和newURL。分别表示变化前的URL和变化后的URL。通常用于Ajax技术。