事件
事件(Event)对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。
事件通常与函数结合使用,函数不会在事件发生前被执行!
例如onload。
onload这个事件会在页面加载完成后触发
当脚本写在标签里,可能会因为没有加载完成而无法获取对象,可以用window.onlock解决。
我们不提倡将后执行的代码写在上面,在网络不通畅时可能影响加载速度。
事件对象
当事件的响应函数触发时,浏览器会将严格事件对象作为实参传给响应函数。事件对象封装了事件的一切属性。
这是一个鼠标定位的例子。
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<head>
<style type="text/css">
#box{
height: 100px;
width: 100px;
background-color: blue;
}
</style>
</head>
<body>
<div id="box">
</div>
<script>
window.onload = function ( ) {
var box = document.getElementById("box");
var body = document.getElementsByTagName("body")[0];
var div =document.createElement("div");
body.appendChild(div);
box.onmousemove = function(event){//这里传入了事件
//var x =event.clientX;
//var y =event.clientY;
var x =window.event.clientX;
var y =window.event.clientY;
div.innerHTML="x"+x+"y"+y;
//鼠标在盒子里移动可以输出其坐标
}
}
</script>
</body>
</body>
</html>
注:坏消息是ie8又双叒不兼容一般写法,event
在ie8中被作为全局属性应写为window.event
,比较好的消息是现在Chrome和FF现在也支持这种写法了我们不用再写event=event||window.event
来解决兼容问题了。
事件流
在学会了事件后我为自己想了一个例子:点击拖动一个元素,松开鼠标放下元素。但因为涉及多个事件造成了混乱,那么事件的发生顺序是怎样的?
那我们来观察点击不同位置,下面五个事件的发生顺序,在实际运行前,不妨先猜测一下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#box{
background: yellow;
}
#box span{
background: greenyellow;
}
</style>
</head>
<body>
<p>点击这里,这里是body</p>
<div id="box">
点击这里,这里是div
<span>点击这里,这里是span</span>
</div>
<script>
var body = document.getElementsByTagName("body")[0];
var box = document.getElementById("box");
var span = box.getElementsByTagName("span")[0];
window.onload = function () {
body.onclick=function () {
alert("body0");
}//body的点击事件
body.onclick=function () {
alert("body1");
}//body的点击事件,与上一个平级
box.onclick = function () {
alert("box");
}//div的点击事件,div为body的子元素
span.onclick = function() {
alert("span");//span的点击事件,span是div的子元素
span.onclick = function() {
alert("span0");
}//嵌套在第一个点击事件的点击事件
}
}
</script>
</body>
</html>
事件的传播
事件流是为解决事件的发生顺序而生,上古时期ie与网景(已经凉了)两家公司分别提出了冒泡和捕获,后来w3c组织整合两者(虽说如此,ie8以下仍然不支持捕获)就是我们正在使用的事件流。
我在大佬那里找到了一张比较清晰的图,来表示事件流的阶段
1. 捕获阶段 由外向内
2.目标阶段 事件到达目标,触发,逆向回流
3. 冒泡阶段 由内向外
事件的等级level
也影响事件的顺序,事件分为三个等级即:level 0
level 2
level 3
默认等级为level 0
,这个等级不支持捕获,而且因为ie8以下不支持捕获,所以level 0
是我们主要使用的等级。
在上面的例子中,我们点击最内侧的span。事件的发生顺序为:span》box》body1 。点击事件由span传递给div,然后向上传递给body,同样冒泡是可以取消的。
event.cancelBubble=ture;
//取消冒泡,取消冒泡不是仅针对当前事件,而是让泡泡在当前位置消失
//当然这个事件本身还是能产泡泡的
让我们再重复一下level 0
的特点:
1.不支持捕获,只支持冒泡
2.一个元素只能绑定一个事件(最后一个事件)
3.事件可以解除绑定
box.onmousemove=null;
//将事件设置为空就可以解除事件
冒泡的特点: 相同事件的发生是由内而外的
现在来完成我们的例子
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<head>
<style type="text/css">
#box{
height: 100px;
width: 100px;
background-color: blue;
position: absolute;
}
</style>
</head>
<body>
<p>拖动方块</p>
<div id="box"></div>
<script>
window.onload = function ( ) {
var body = document.getElementsByTagName("body")[0];
var div =document.createElement("div");
body.appendChild(div);
var box = document.getElementById("box");
box.onmousemove = function(event){
var x =window.event.clientX;
var y =window.event.clientY;
div.innerHTML="当前坐标:x="+x+"y="+y;
}
box.onmousedown=function(){//鼠标按下,mousedown是瞬时的行为,你不能仅靠她来完成拖动,只能点一下动一动
document.onmousemove= function (event) {//绑定移动
move(event);//我们把移动事件给全局防止鼠标跑的太快事件脱离
}
}
box.onmouseup=function () {//鼠标弹起
document.onmousemove=null;//解除move的绑定
}
function move(event) {//方法--用于移动方块
var x =window.event.clientX;
var y =window.event.clientY;
box.style.left = x-box.scrollHeight/2+"px";
box.style.top = y-box.scrollWidth/2+"px";
}
}
</script>
</body>
</html>
事件委派
之前我们对一系列于单击相应函数采用遍历的方法绑定,这种方法麻烦而且效率低下; 当事件的祖先被绑定单击相应函数,他的子元素会不触发这个函数?会的,因为冒泡的存在。
利用冒泡将事件绑定给祖先元素,减少绑定次数叫做事件的委派。
但先别高兴太早,如果单纯的将事件绑定给祖先元素那么范围是不是太大了?所以我们要让我们所期望的事件触发事件,那什么可以帮助我们呢?Event手册
target 返回触发此事件的元素(事件的目标节点)。
if(window.event.target.className=="link"){//只有class为link的元素才能触发事件
del();
}
监听器
我们之前说过,事件等级level 0
只支持绑定一个事件,但有的时候一个事件确实不够用。这时候我们就要用到level 2
(但请不要忘记ie 8不兼容)
我们先来认识一下监听器
addEventListener("事件字符串",function(){},false);
1.参数一为字符串;内容为零级响应事件去掉on前缀,比如onclick
写为click
2.参数二为回调函数,就是事件触发时调用的
3.参数三是否在捕获阶段触发?我们一般不要这样做,所以写false
监听器的绑定不受数量限制,我们可以为相同事件绑定多个响应函数,同级事件按顺序执行。
对于ie 8 的兼容
attachEvent("onclick",function(){});
1.参数一,正常书写响应事件
2.参数二,回调函数
3.没有参数三,ie 8 不支持捕获
4.事件的执行顺序是自下向上
兼容性的解决思路与之前一样
window.onload=function () {
bind(span,"click",log);
}
function bind(obj,eventStr,callback) {
if(obj.addEventListener){
obj.addEventListener(eventStr,callback,false);
}else {
obj.attachEvent("on"+eventStr,callback);
}
}
function log(){
alert("span");
}
为什么我们默认没有on呢?显然加on比删除要容易。
常用事件
滚轮
.onmousewheel//滑动滚轮
/*
火狐不兼容这个事件,应使用DOMMouseScroll,而且只能由监听器触发
*/
box.onmousewheel = function () {
alert(eve);
}
box.addEventListener("DOMMouseScroll",box.onmousewheel,false);
之前我们解决兼容性问题通常是使用if判断,
但在Chrome中if( box.onmousewheel)会返回false,内存中onmousewheel=null
火狐中没有 box.onmousewheel但把他当做了函数名不会报错
chrom中没有DOMMouseScroll事件但同样不会报错也不会触发
于是我们在火狐中将这个事件当做函数名使用解决兼容性问题
但实际上这种解决问题的方式稍微进一步就会失效,比如:我想要进一步判断滚轮滑动方向就完蛋了。
function up(){
var he = getComputedStyle(box,null).height;
var str =he.split("px")[0];
str = Number(str);
box.style.height = str +100+"px";
}
function down(){
var he = getComputedStyle(box,null).height;
var str =he.split("px")[0];
str = Number(str);
if(str>100){
box.style.height = str -100+"px";
}else{
box.style.height ="0px";
}
}
box.onmousewheel = function () {//chrome
if(event.wheelDelta>0){
up();
}else{
down();
}
}
box.addEventListener("DOMMouseScroll",function () {//火狐
if(event.detail<0){
up();
}else{
down();
}
},false);
event.whellDelta//用于判断滚轮滑动方向;
向上为正,向下为负;我们只需要正负因为……每个浏览器都不一样
event.detail//火狐专用;向上为负,向下为正
按键
键盘事件一般绑定给可以获取焦点的对象或者document。(获取不了焦点怎么获取键盘事件?)
onkeydown;//当按键按下持续发生(第一次和第二次间隔略长是正常的防误触操作)
onkeyup;//当按键松开
通过eventkeycode或者event.which获取按键编码,
String.fromCharCode(event.which);可以直接转换编码为字符
组合按键
我们想要确定ctrl按下需要event.keycode ==17;
我们想要确定c按下需要event.keycode ==67;
那么判断两个键同时按下呢?event.keycod不能同时等于两个值啊?
属性 | 事件 |
---|---|
altkey | 返回当事件被触发时,“ALT” 是否被按下。 |
ctrlkey | 返回当事件被触发时,“CTRL” 键是否被按下。 |
meta | 返回当事件被触发时,“meta” 键是否被按下。 |
shiftkey | 返回当事件被触发时,“SHIFT” 键是否被按下。 |
if(event.keyCode ==67 && event.ctrlkey)
//这样就可以判断一对组合键