DOM高级
事件模型
- 基本事件模型:也称为DOM0事件模型,是浏览器初期出现的一种比较简单的事件模型,主要通过HTML事件属性,为指定标签绑定事件处理函数。由于这种模型应用比较广泛,获得了所有浏览器的支持,目前依然比较流行。但是这种模型对于HTML文档标签依赖严重,不利于JavaScript独立开发
- DOM事件模型:由W3C制订,是目前标准的事件处理模型。所有符合标准的浏览器都支持该模型,IE怪异模式不支持。DOM事件模型包括DOM2事件模块和DOM3事件模块,DOM3事件模块为DOM2事件模块的升级版,略有完善,主要是新增了一些事情类型,以适应移动设备的开发需要,但大部分规范和用法保持一致。
- IE事件模型:IE4.0及其以上版本浏览器支持,与DOM事件模型相似,但用法不同
- Netscape事件模型:由 Netscape4浏览器实现,在 Netscape6中停止支持
事件流
事件流就是多个节点对象对同一种事件进行响应的先后顺序,主要包括以下3种类型
-
冒泡型 事件从最特定的目标向最不特定的目标( document对象)触发,也就是事件从下向上进行响应,这 个传递过程被形象地称为“冒泡”
-
捕获型 事件从最不确定的目标(document对象)开始触发,然后到最特定的目标,也就是事件从上向下进行相应
-
混合型 w3C的DOM事件模型支持捕获型和冒泡型两种事件流,其中捕获型事件流先发生,然后才发生冒泡型事件流。两种事件流会触及DOM中的所有层级对象,从 document对象开始,最后返回 document对象结束。因此,可以把事件传播的整个过程分为3个阶段
- 捕获阶段:事件从 document对象沿着文档树向下传播到目标节点,如果目标节点的任何一个上级节点注册了相同的事件,那么事件在传播的过程中就会首先在最接近顶部的上级节点执行,依次向下传播
- 目标阶段:注册在目标节点上的事件被执行
- 冒泡阶段:事件从目标节点向上触发,如果上级节点注册了相同的事件,将会逐级响应,依次向上传播
![]()
绑定事件
- 静态绑定:把JS脚本作为属性值,直接赋值给事件属性
- 动态绑定:使用DOM对象的事件属性进行赋值
- 事件处理函数:事件处理函数是一类特殊的函数,与函数直接量结构相同,主要任务是实现事件处理,为异步调用,由事件触发进行相应。
绑定事件的事件机制(DOM0事件)
使用on+事件名这种方式注册的事件叫做DOM0级事件 所有浏览器都支持这种事件绑定
var oOuter = my.getID("outer");
var oInner = my.getID("inner");
var oCon = my.getID("con");
//DOM 0级事件 在所有浏览器中都是冒泡的形式
oOuter.onclick = function () {
alert("outer");
}
oInner.onclick = function () {
alert("inner");
}
oCon.onclick = function () {
alert("con");
}
var oBox = document.getElementById("box");
/*使用DOM0级事件 对同一个元素绑定同一个事件 只能执行一次
后边的绑定会把前边的绑定给覆盖掉*/
/*oBox.onclick = function () {
alert(1);
}
oBox.onclick = function () {
alert(2);
}
oBox.onclick = function () {
alert(3);
}
oBox.onclick = function () {
alert(4);
}*/
oBox.onclick = function () {
alert(4);
}
// 取消DOM 0 级事件 直接给事件一个null即可
document.onclick = function () {
oBox.onclick = null;
}
注册事件
- 在DOM事件模型中,通过调用对象的addEventListnenr()方法注册事件
- type:注册事件的类型名,事件类型与事件属性不同,事件类型名没有on前缀,例如,对于事件属性 onclick来说,所对应的事件类型为 click
- listener:监听函数,即事件处理函数,在指定类型的事件发生时将调用该函数,在调用这个函数时,默认传递给它的唯一参数是 event对象
- useCapture:是一个布尔值,如果为true,则指定的事件处理函数将在事件传播的捕获阶段触发,如果为 false,则事件处理函数将在冒泡阶段触发
- 使用 addEventListener()方法能够为多个对象注册相同的事件处理函数,也可以为同一个对象注册多件处理函数。为同一个对象注册多个事件处理函数对于模块化开发非常有用。
- IE事件模型使用attachEvent(etype,eventName)
- type:事件类型:onclick、onkeyup等
- eventName:设置事件处理函数
- 使用attachEvent注册事件时,其事件处理函数的调用对象不再是当前事件对象的本身,而是window对象,如果想要获取当前对象,则使用event事件对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册事件(事件监听)</title>
</head>
<body>
<div id="demo">demo</div>
<div id="outer">
<div id="inner">
<div id="con">
k看我的事件流
</div>
</div>
</div>
<script>
var oDemo = document.getElementById("demo");
/*oDemo.addEventListener("click",function () {
alert("demo1");
},false);
oDemo.addEventListener("click",function () {
alert("demo2");
},false);
oDemo.addEventListener("click",function () {
alert("demo3");
},false);
oDemo.addEventListener("click",function () {
alert("demo4");
},false);*/
var oOuter = document.getElementById("outer");
var oInner = document.getElementById("inner");
var oCon = document.getElementById("con");
/*oOuter.addEventListener("click",function () {
alert("outer")
},false)
oInner.addEventListener("click",function () {
alert("inner")
},true)
oCon.addEventListener("click",function () {
alert("con")
},true)*/
// IE低版本事件监听
/*oCon.attachEvent("onclick",function () {
alert(1);
})
oInner.attachEvent("onclick",function () {
alert(2);
})*/
</script>
</body>
</html>
销毁事件
- 在DOM事件模型中,使用removeEventListener()方法可以从指定对象中删除已经注册的事件处理函数
- removeEventListener()只能处理addEventListener方法注册的事件
- 当临时注册一个事件时,可以在处理完毕后删掉它,这样能够节省系统资源
- IE事件模型使用detachEvent方法注销事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="box">点击我有惊喜哦</div>
<button id="btn">取消惊喜</button>
<script>
var oBox = document.getElementById("box");
var oBtn = document.getElementById("btn");
/*oBox.onclick = function () {
alert("圣诞快乐");
}
//点击btn 取消box的DOM0点击事件
oBtn.onclick = function () {
oBox.onclick = null;
}*/
// 必须保证绑定的函数和移除的函数是同一个函数
/*function f(){
alert("圣诞快乐")
}
oBox.addEventListener("click",f,false);
//点击btn 取消box的DOM2点击事件
oBtn.onclick = function () {
oBox.removeEventListener("click",f)
}*/
function f(){
alert("圣诞快乐")
}
oBox.attachEvent("onclick",f);
oBtn.onclick = function () {
oBox.detachEvent("onclick",f)
}
</script>
</body>
</html>
绑定事件兼容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DOM2级事件的兼容</title>
</head>
<body>
<button id="btn">移除事件</button>
<div id="box">
box
</div>
<script src="./my.js"></script>
<script>
var oBox = document.getElementById("box");
var oBtn = document.getElementById("btn");
function fn1() {
alert("看我");
}
/*function addEvent(ele,type,fn,boo) {
// DOM2级事件绑定兼容性封装
if (ele.addEventListener){
ele.addEventListener(type,fn,boo||false);
}else if (ele.attachEventhEvent){
ele.attachEvent("on"+type,fn)
}else{
ele["on"+type] = fn;
}
}*/
my.addEvent(oBox,"click",fn1)
/*function removeEvent(ele,type,fn){
if (ele.removeEventListener){
ele.removeEventListener(type,fn);
}else if(ele.detachEvent){
ele.detachEvent("on"+type,fn)
}else{
ele["on" + type] = null;
}
}*/
oBtn.onclick = function () {
my.removeEvent(oBox,"click",fn1)
}
/*// DOM2级事件绑定兼容性封装
if (oBox.addEventListener){
oBox.addEventListener("click",fn1,false);
}else if (oBox.attachEvent){
oBox.attachEvent("onclick",fn1)
}else{
oBox.onclick = fn1;
}
oBtn.onclick = function () {
if (oBox.removeEventListener){
oBox.removeEventListener("click",fn1);
}else if(oBox.detachEvent){
oBox.detachEvent("onclick",fn1)
}else{
oBox.onclick = null;
}
}*/
</script>
</body>
</html>
DOMContentLoaded事件
- window.onload当所有的节点和资源加载完成才执行
- 加载需要等待资源加载 并且还只能对window绑定一次
- 解决方法1: 仍然是等资源加载完成才执行
- 解决方法2 使用DOMContentLoaded事件 :当所有节点加载完毕就可以执行
- DOMContentLoaded是DOM2级的事件 需要使用DOM2的监听方式来绑定事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DOMContentLoaded</title>
<script>
// window.onload当所有的节点和资源加载完成才执行
// 加载需要等待资源加载 并且还只能对window绑定一次
/*window.onload = function () {
var oBox = document.getElementById("box");
oBox.onclick = function () {
alert(1);
}
}*/
//解决方法1: 仍然是等资源加载完成才执行
/*window.addEventListener("load",function () {
var oBox = document.getElementById("box");
oBox.onclick = function () {
alert(1);
}
})*/
//解决方法2 使用DOMContentLoaded事件 :当所有节点加载完毕就可以执行
// onDOMContentLodeaded是DOM2级的事件 需要使用DOM2的监听方式来绑定事件
window.addEventListener("DOMContentLoaded",function () {
var oBox = document.getElementById("box");
oBox.onclick = function () {
alert(1);
}
},false)
</script>
</head>
<body>
<div id="box">1111</div>
</body>
</html>
event对象
- event对象由事件自动创建,记录了当前事件的状态,如事件发生的源节点、键盘按键的响应状态、鼠标指针的移动位置、鼠标按键的响应状态等信息,
- event对象的属性提供了有关事件的细节,其方法可以控制事件的传播
- 2级DOM Events规范定义了一个标准的事件模型,它被除了IE低版本以外的所有现代浏览器所实现,而IE定义了专用的、不兼容的模型。简单比较两种事件模型如下:在DOM事件模型中, event对象被传递给事件处理函数,但是在IE事件模型中,它被存储在window对象的event属性中
- bubbles:返回布尔值,指示事件是否是冒泡事件类型。如果事件是冒泡类型,则返回tue:否则返回 fasle
- cancelable:返回布尔值,指示事件是否可以取消的默认动作,如果使用 preventDefault方法可以取消与事件关联的默认动作则返回值为mue:否则为false
- target:返回事件的目标节点
- type:事件类型
- preventDefault():通知浏览器不要执行与事件关联的默认动作
- stopPropagation():阻止事件在捕获、目标、冒泡阶段的进一步传播
var oBox = document.getElementById("box");
/*oBox.onclick = function () {
console.log(window.event);
// console.log(1);
}
oBox.onclick = function (e) {
console.log(e);
// console.log(1);
}*/
// 兼容性获取event事件对象:
oBox.onclick = function (e) {
var e = e || window.event;
console.log(e);
}
event事件的鼠标定位
- clientX:以浏览器窗口左上顶角为原点,定位x轴坐标
- offsetX:以当前事件的目标对象左上顶角为原点,定位x轴坐标
- pageX:以 document对象(即文档窗口)左上顶角为原点,定位x轴坐标(不兼容IE)
- screenX:计算机屏幕左上顶角为原点,定位x轴坐标
var oCon = document.getElementById("con");
oCon.onclick = function (e) {
var e = e || window.event;
// console.log(e.clientX,e.clientY);
// console.log(e.offsetX,e.offsetY);
// console.log(e.pageX,e.pageY);
// console.log(e.screenX,e.screenY);
console.log(getEventPage(e));
}
// pageX和pageY的封装
function getEventPage(e) {
if (e.pageX){
return {
x:e.pageX,
y:e.pageY
}
}else{
return {
x:document.body.scrollLeft + e.clientX,
y:document.body.scrollTop + e.clientY
}
}
}
阻止传播
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>阻止传播</title>
<style>
#outer{
width: 100px;
height: 100px;
background-color: red;
}
#inner{
width: 100px;
height: 50px;
background-color: yellow;
}
#box{
width: 100px;
height: 20px;
background-color: pink;
}
</style>
</head>
<body>
<div id="outer">
<div id="inner">
<div id="box">box</div>
inner
</div>
outer
</div>
<script>
var oOuter = document.getElementById("outer");
var oInner = document.getElementById("inner");
var oBox = document.getElementById("box");
oOuter.addEventListener("click",function (ev) {
// ev.stopPropagation?ev.stopPropagation():ev.cancelBubble = true;
alert(1);
},true);
oInner.addEventListener("click",function () {
alert(2);
},true);
oBox.addEventListener("click",function (ev) {
// 阻止传播
// 现代浏览器中:
/* ev.stopPropagation();
// ie678浏览器中
ev.cancelBubble = true;*/
// ev.stopPropagation?ev.stopPropagation():ev.cancelBubble = true;
alert(3);
},true);
</script>
</body>
</html>
阻止默认事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>阻止默认事件</title>
</head>
<body>
<a id="a1" href="http://www.baidu.com">百度一下你就知道</a>
<script>
var oA1 = document.getElementById("a1");
oA1.onclick = function (ev) {
var ev = ev || window.event;
// 阻止默认事件
/*在现代浏览器:
ev.preventDefault();
在IE678:
ev.returnValue = false;*/
/*if(ev.preventDefault){
ev.preventDefault();
}else{
ev.returnValue = false;
}*/
// ev.preventDefault?ev.preventDefault():ev.returnValue = false;
return false;//如果说用来阻止默认事件,必须写在函数的最下边 因为他下边的代码不再执行
}
</script>
</body>
</html>
键盘事件
键盘事件
- 当用户操作键盘的时候会触发键盘事件
- keydown:键盘被按下某个按键的时候触发,如果按住某一个按键,会不断触发该事件
- keyup:释放某一个按键的时候触发。不是持续相应状态
document.onkeydown = function (e) {
var e = e || window.event;
console.log(e);
}
键盘事件属性
-
键盘事件定义了很多属性
-
keyCode:对应键盘中对应键位的键值
-
shiftKey、ctrlKey、altKey是否按下shift strl alt按键 返回布尔值
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>键码</title> </head> <body> Jintiantianqizhenhao <script> document.onkeydown = function (ev) { /*var ev = ev || window.event; // console.log(ev) if (ev.keyCode == 67 && ev.ctrlKey) { alert("你又来复制了?"); } return false;*/ console.log(1); } </script> </body> </html>
### 键盘控制移动
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>键盘控制移动</title>
<style>
#box{
width: 100px;
height: 100px;
background-color: red;
position: absolute;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div id="box">
</div>
<script>
var oBox = document.getElementById("box");
/*document.onkeydown = function (ev) {
// console.log(1);
var ev = ev || window.event;
if(ev.keyCode == 39){
oBox.style.left = oBox.offsetLeft + 1 + 'px';
}
if(ev.keyCode == 38){
oBox.style.top = oBox.offsetTop - 1 + 'px';
}
if(ev.keyCode == 37){
oBox.style.left = oBox.offsetLeft - 1 + 'px';
}
if(ev.keyCode == 40){
oBox.style.top = oBox.offsetTop + 1 + 'px';
}
}*/
var shang = false,xia = false,zuo = false,you = false;
var x = 0,y = 0;
document.onkeydown = function (ev) {
var ev = ev || window.event;
/*if (ev.keyCode == 38){
shang = true;
}
if (ev.keyCode == 39){
you = true;
}
if (ev.keyCode == 40){
xia = true;
}
if (ev.keyCode == 37){
zuo = true;
}*/
switch (ev.keyCode){
case 38:
shang = true;
break;
case 39:
you = true;
break;
case 40:
xia = true;
break;
case 37:
zuo = true;
break;
}
}
document.onkeyup = function (ev){
var ev = ev || window.event;
switch (ev.keyCode){
case 38:
shang = false;
break;
case 39:
you = false;
break;
case 40:
xia = false;
break;
case 37:
zuo = false;
break;
}
}
timer = setInterval(function () {
if (shang){
y --;
}
if(xia){
y ++

