事件对象
什么是event对象和事件冒泡
- 获取事件的详细信息:鼠标位置,键盘按键
- 例子:获取鼠标位置:clientX
- document的本质:document.childNodes[0].tagName
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
window.onload = function() {
document.body.onclick = function() {
alert('a');
};
};
</script>
</body>
</html>
点击网页,是没有反应的,因为body里面什么也没有啊,没有被撑开,但是如果把document.body.onclick 换成document.onclick,就可以了,因为document代表的是整个网页啊。
关于document
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript">
window.onload = function() {
alert(document.childNodes[0].tagName);
};
</script>
</head>
<body>
</body>
</html>
alert(document.childNodes[0].tagName);// !
alert(document.childNodes[1].tagName);// HTML
DOCUTYPE其实也是一个节点,而且,DOCUTYPE和HTML两个节点有个共同的父级,就是document,理解为整个网页!
所以,以后给整个页面加事件的时候,一定要给document加,而不是body
事件对象
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript">
window.onload = function() {
document.onclick = function() {
alert(event.clientX + ',' + event.clientY);
};
};
</script>
</head>
<body>
</body>
</html>
在FireFox中,不认识event,在浏览器中,事件函数都带有一个参数的,就是 事件对象,系统传来的。
最终的兼容方案:
var oEvent = ev||event;
window.onload = function() {
document.onclick = function(ev) {
var oEvent = ev || event;
alert(oEvent.clientX + ',' + oEvent.clientY);
};
};
事件流
事件冒泡
<!DOCTYPE html>
<html onclick="alert('html');">
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
div {
padding: 100px;
}
</style>
<script type="text/javascript">
window.onload = function() {
document.onclick = function() {
};
};
</script>
</head>
<body onclick="alert('body');">
<div style="background: yellow;" onclick="alert(this.style.background);">
<div style="background: green;" onclick="alert(this.style.background);">
<div style="background: red;" onclick="alert(this.style.background);"></div>
</div>
</div>
</body>
</html>
在红色块中点击一下,依次弹出:red -> green -> yellow -> body -> html
事件冒泡顺序:red div -> green div -> yellow div -> body -> html -> document
冒泡,有时候有些用途,但大多数会带来一些麻烦
比如:
页面上一个小按钮,点击一下,下面的灰色临时div出来,点击网页其他部分,灰色临时div消失。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
div {
width: 400px;
height: 300px;
background: #CCC;
display: none;
}
</style>
<script type="text/javascript">
window.onload = function() {
var oBtn = document.getElementById('btn1');
var oDiv = document.getElementById('div1');
oBtn.onclick = function() {
oDiv.style.display = 'block';
alert('按钮被点击');
};
document.onclick = function() {
oDiv.style.display = 'none';
alert('document被点击');
};
};
</script>
</head>
<body>
<input id="btn1" type="button" value="show" />
<div id="div1"></div>
</body>
</html>
这样,你会发现,点击按钮,灰色临时div根本不会出来!
原因很简单,当你点击按钮的时候,那一瞬间,灰色临时div的确出现了,但冒泡了,事件不仅点到btn上,但也冒泡到document上了,所以也就是给document也传了一个事件,那么立刻就又display:none了。
取消冒泡
oEvent.cancelBubble = true;
鼠标事件
clientX , clientY
onmusemove
灰色小div跟着鼠标到处跑
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
div {
width: 40px;
height: 40px;
background: #CCC;
position: absolute;
}
</style>
<script type="text/javascript">
document.onmousemove = function(ev) {
//灰色小div跟着鼠标到处跑
var oEvent = ev || event;
var oDiv = document.getElementById('div1');
oDiv.style.left = oEvent.clientX + 'px';
oDiv.style.top = oEvent.clientY + 'px';
};
</script>
</head>
<body>
<div id="div1"></div>
</body>
</html>
其实,这个程序有很大的漏洞,那就是不理解clientX和clientY,如果body给个高度,比如2000px,那么,灰色小块就会和鼠标脱离。clientX是鼠标位置在可视区到左边的距离,如果网页很大,根本不止一屏幕,那么可视区只是整个网页的一部分,这时候,可视区如果不是网页的最顶端部分,而是网页卷去了一部分,也就是scrollTop>0了,“==oDiv.style.top = oEvent.clientY + ‘px’;==”这句话就出问题了,top值这时候大于clientY了。也即是说,clientX 和 clientY是根据可视区定位的,但是,div可是根据body定位的(left,top)。
法则:
但凡是用到clientX,clientY的时候,一定用到scrollLeft,scrollTop,不然几乎是一定会出问题的.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
div {
width: 40px;
height: 40px;
background: #CCC;
position: absolute;
}
</style>
<script type="text/javascript">
document.onmousemove = function(ev) {
var oEvent = ev || event;
var oDiv = document.getElementById('div1');
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
oDiv.style.left = oEvent.clientX + 'px';
oDiv.style.top = oEvent.clientY + 'px';
};
</script>
</head>
<body>
<div id="div1"></div>
</body>
</html>
封装scrollTop和scrollLeft
因为经常用到,写起来麻烦,封装成库
function getPos(ev) {
var st = document.documentElement.scrollTop || document.body.scrollTop;
var sl = document.documentElement.scrollLeft || document.body.scrollLeft;
return {x:ev.clientX+sl, y:ev.clientY+st};
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
div {
width: 40px;
height: 40px;
background: #CCC;
position: absolute;
}
</style>
<script type="text/javascript">
function getPos(ev) {
var st = document.documentElement.scrollTop || document.body.scrollTop;
var sl = document.documentElement.scrollLeft || document.body.scrollLeft;
return {x:ev.clientX+sl, y:ev.clientY+st};
}
document.onmousemove = function(ev) {
var oEvent = ev || event;
var oDiv = document.getElementById('div1');
var pos = getPos(oEvent);
oDiv.style.left = pos.x + 'px';
oDiv.style.top = pos.y + 'px';
};
</script>
</head>
<body style="height: 30000px">
<div id="div1"></div>
</body>
</html>
下面的功能是很多个div,跟在鼠标后面一大串
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
div {
width: 50px;
height: 50px;
background: red;
position: absolute;
left: 300px;
top: 200px;
}
img {
width: 100%;
height: 100%;
}
</style>
<script type="text/javascript">
function getPos(ev) {
var st = document.documentElement.scrollTop || document.body.scrollTop;
var sl = document.documentElement.scrollLeft || document.body.scrollLeft;
return {x:ev.clientX+sl, y:ev.clientY+st};
}
var k = 0;
document.onmousemove = function(ev) {
k++;
var oEvent = ev || event;
var pos = getPos(oEvent);
var aDiv = document.getElementsByTagName('div');
var len = aDiv.length;
aDiv[0].style.left = pos.x + 'px';
aDiv[0].style.top = pos.y + 'px';
for (var i = len - 1; i > 0; i--) {
aDiv[i].style.left = aDiv[i - 1].offsetLeft + 'px';
aDiv[i].style.top = aDiv[i - 1].offsetTop + 'px';
}
};
</script>
</head>
<body>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
<div><img src="http://pic.58pic.com/58pic/13/59/88/32W58PICQpk_1024.jpg"></div>
</body>
</html>
键盘事件,keyCode
onkeydown
onkeyup
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>zns</title>
</head>
<body>
<script type="text/javascript">
document.onkeydown = function(ev) {
var oEvent = ev || event;
alert(oEvent.keyCode);
};
</script>
</body>
</html>
a:65 b:66 ......
要求:键盘控制div的移动
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>zns</title>
<style type="text/css">
#div1 {
width: 100px;
height: 100px;
background: red;
position: absolute;
}
</style>
</head>
<body>
<div id="div1"></div>
<script type="text/javascript">
var oDiv = document.getElementById('div1');
document.onkeydown = function(ev) {
var oEvent = ev || event;
var code = oEvent.keyCode;
switch(code) {
case 37:
oDiv.style.left = oDiv.offsetLeft - 5 + 'px';
break;
case 38:
oDiv.style.top = oDiv.offsetTop - 5 + 'px';
break;
case 39:
oDiv.style.left = oDiv.offsetLeft + 5 + 'px';
break;
case 40:
oDiv.style.top = oDiv.offsetTop + 5 + 'px';
break;
}
};
</script>
</body>
</html>
上面代码,满足了左键右键移动div的要求,但是,基于系统本身的特点(原因:系统要区分用户是否连续输入,第一个到第二个之间有一个停顿时间。比如,当你长按a的时候,屏幕上先是出现一个a,顿一下然后才出现第二个第三个一串a,这是系统为了考虑行动缓慢的老人,故意延迟一下时间,因为老人按的比较慢,避免出现一串a)但也同时造成了我们的困扰,你按一下左键,也是顿一下,这是不行的,如何解决??解决方案:先开一个定时器,让div一直处于(往4个方向)准备移动的状态(初始4个方向的值都是false,div就保持在原地不动),当按下某个方向键,这个方向的值就改变为true,div就会开始往这个方向移动,松开方向键,这个方向的值就改变为false , div就停止这个方向移动了
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>zns</title>
<style type="text/css">
#div1 {
width: 100px;
height: 100px;
background: red;
position: absolute;
}
</style>
</head>
<body>
<div id="div1"></div>
<script type="text/javascript">
var oDiv = document.getElementById('div1');
var key_left = false;
var key_right = false;
var key_bottom = false;
var key_top = false;
var timer = null;
setInterval(function() {
if(key_left) {
oDiv.style.left = oDiv.offsetLeft - 5 + 'px';
} else if(key_right) {
oDiv.style.left = oDiv.offsetLeft + 5 + 'px';
} else if(key_top) {
oDiv.style.top = oDiv.offsetTop - 5 + 'px';
} else if(key_bottom) {
oDiv.style.top = oDiv.offsetTop + 5 + 'px';
}
}, 50);
document.onkeydown = function(ev) {
var oEvent = ev || event;
var code = oEvent.keyCode;
switch(code) {
case 37:
key_left = true;
break;
case 38:
key_top = true;
break;
case 39:
key_right = true;
break;
case 40:
key_bottom = true;
break;
}
};
document.onkeyup = function(ev) {
var oEvent = ev || event;
var code = oEvent.keyCode;
switch(code) {
case 37:
key_left = false;
break;
case 38:
key_top = false;
break;
case 39:
key_right = false;
break;
case 40:
key_bottom = false;
break;
}
};
</script>
</body>
</html>
#### 需求:回车键按下,input框内的内容追加到textarea中
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>zns</title>
<style type="text/css">
#div1 {
width: 100px;
height: 100px;
background: red;
position: absolute;
}
</style>
</head>
<body>
<input id="txt1" type="text" /><br>
<textarea id="txt2" rows="10" cols="40" style="margin-top: 10px;"></textarea>
<script type="text/javascript">
var oTxt1 = document.getElementById('txt1');
var oTxt2 = document.getElementById('txt2');
// oTxt1内写完时候,焦点在oTxt1内,这时候回车,keydown应该加在oTxt1上
oTxt1.onkeydown = function(ev) {
var oEvent = ev || event;
if(oEvent.keyCode == 13) {
oTxt2.value += oTxt1.value + '\n';
oTxt1.value = '';
}
};
</script>
</body>
</html>
需求:回车和Ctrol键同时按下才提交
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>zns</title>
<style type="text/css">
#div1 {
width: 100px;
height: 100px;
background: red;
position: absolute;
}
</style>
</head>
<body>
<input id="txt1" type="text" /><br>
<textarea id="txt2" rows="10" cols="40" style="margin-top: 10px;"></textarea>
<script type="text/javascript">
var oTxt1 = document.getElementById('txt1');
var oTxt2 = document.getElementById('txt2');
// oTxt1内写完时候,焦点在oTxt1内,这时候回车,keydown应该加在oTxt1上
oTxt1.onkeydown = function(ev) {
var oEvent = ev || event;
if(oEvent.keyCode == 13 && oEvent.ctrlKey) {
oTxt2.value += oTxt1.value + '\n';
oTxt1.value = '';
}
};
</script>
</body>
</html>