目录 |
1.什么是事件
2.事件对象及兼容处理
3.事件的传播机制
4.案例-鼠标跟随jQuery
5.案例-鼠标跟随JS版
6.鼠标跟随、深入理解事件的传播机制
7.事件委托/事件代理
8.案例-京东商城放大镜
9.案例-百度搜索框
10.案例-多级菜单JS版
11.案例-多级菜单jQuery版
12.拖拽demo实现基本的效果
13.拖拽demo解决鼠标丢失
1.什么是事件 |
事件分为两部分:
1.行为本身:浏览器天生就赋予其的行为。onclick、onmouseover(onmouserenter)、onmouseout(onmouseleave)、onmousemove、ommousemove、onmousedown、onmouseup、onmousewheel(鼠标滚轮滚动行为)、onscroll(滚动条滚动行为)、onresize(window.onresize 浏览器窗口大小改变事件)、onload、onunload、onfouse文本框获取焦点行为)、onblur(浏览器失去焦点)、onkeydown(键盘按下行为)、onkeyup……
哪怕没有给上述行为绑定方法,事件也存在。当点击这个盒子的时候,同样会触发它的onclick行为,只是什么事情都没做而已。
2.事件绑定:给元素的某一个行为绑定一个方法
//DOM0级事件绑定
var oDiv = document.getElementById("div1");
oDiv.onclick = function () {
//当触发oDiv的onclick行为的时候,会把绑定的这个函数执行
};
//DOM2级事件绑定
oDiv.addEventListener("click", function () {
console.log("ok");
}, false);
onclick这个行为定义在当前元素的私有属性上;
addEventListener这个属性是定义在当前元素所属EventTarget这个类的原型上的
2.事件对象及兼容处理 |
oDiv.onclick = function () {
};
把匿名函数定义的部分当做一个值赋值给oDiv的点击行为(函数表达式)
当触发div的点击行为的时候,会执行对应绑定上的方法
不仅仅把绑定的方法执行了,而且浏览器还默认的给这个方法传递了一个参数值:MouseEvent:鼠标事件对象。
- MouseEvent是一个对象数据类型值,里面包含了很多的属性名和属性值,这些都是用来记录当前鼠标的相关信息的
- MouseEvent -> UIEvent -> Event -> Object
- MouseEvent记录的是页面中唯一一个鼠标每一次触发时候的相关信息,和到底是在哪个元素上触发的没有关系
关于事件对象(MouseEvent)的兼容性问题:
1、事件对象本身的获取存在兼容问题:标准浏览器中是浏览器给方法传递的参数,只需要定义形参e就可以获取到
oDiv.onclick = function (e) {
console.log(e);
};
2、在IE6-8中,浏览器不会给方法传递参数,如果需要的话,需要到window.event中获取查找。
解决方法:
oDiv.onclick = function (e) {
e = e || window.event;
console.log(e);
};
常用信息:
- e.clientX/e.clientY:鼠标触发点距离当前屏幕左上角的坐标值
- e.type:存储的是当前鼠标触发的行为类型,如“click”
- e.target:事件源,当前鼠标触发的是哪个元素,那么它存储的就是哪个元素。存在兼容性问题,在IE6-8中不存在这个属性,即为undefined,可以使用e.srcElement来获取事件源。解决方法:
e.target = e.target || e.srcElement;
- e.preventDefault:阻止浏览器的默认行为。如a标签的默认行为就是跳转页面,但是有时候使用a标签,只是想应用它的特殊性,并不想点击的时候跳转。存在兼容性问题,在IE6-8中不存在这个属性,需要使用e.returnValue = false;来代替。
a.onclick = function (e) {
e = e || window.event;
e.preventDefault ? e.preventDefault() : e.returnValue = false;
//或者:return false;
//或者:见下
};
<li><a href="javascript:;"></a></li>
/*
直接在HTML结构上阻止
或者:href="javascript:void 0;"
href="javascript:void 1;"
*/
- e.pageX/e.pageY:当前鼠标触发点距离body左上角(页面第一屏幕最左上角)的x/y轴的坐标。存在兼容性问题,在IE6-8中不存在这个属性,即为undefined,解决方法:
e.pageX = e.pageX || (e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));
e.pageY = e.pageY || (e.clientY + (document.documentElement.scrollTop || document.body.scrollTop));
- e.stopPropagation:阻止事件的冒泡传播,在IE6-8中不存在这个属性,解决方法如下:
e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true;
- e.keycode:当前键盘上每一个键对应的值,如:空格:32;回退键:8;回车键:13;delete:46;左:37;上:38;右:39;下:40
3.事件的传播机制 |
有以下代码:
<body>
<div id="outer">
<div id="inner">
<div id="center"></div>
</div>
</div>
<script type="text/javascript">
var outer = document.getElementById("outer"),
inner = document.getElementById("inner"),
center = document.getElementById("center");
document.body.onclick = function () {
console.log("body");
};
outer.onclick = function () {
console.log("outer");
};
inner.onclick = function () {
console.log("inner");
};
center.onclick = function () {
console.log("center");
};
</script>
</body>
点击时,控制台会输出:center、inner、outer、body,这就涉及到了事件的默认传播机制。
事件的默认传播机制分为三个阶段:
- 捕获阶段:从外向里依次查找元素
- 目标阶段:当前事件源本身的操作
- 冒泡阶段:从内到外依次触发相关的行为
最常用的就是冒泡阶段。
用DOM0级事件绑定给元素的某一个行为绑定的方法,都是在行为触发后的冒泡阶段把方法执行的。如图:
冒泡阶段:
- 当前center的click行为被触发,如果给其绑定了方法,首先把center对应的方法执行(目标阶段)
- 不仅仅center的click行为被触发了,它所有的父级元素的click行为也会被触发。inner的click行为触发->如果给inner也绑定了方法,inner对应的方法也会执行
- 同理依次查找outer、body、html、document
注意:每个浏览器传播到的最顶层是不一样的。谷歌中可以到document,IE中只能传播到HTML。
document.body.addEventListener("click", function () {
console.log("body");
}, false); //第一个参数是行为的类型,第二个参数是给当前的行为绑定的方法,第三个参数是控制在哪个阶段发生,true是捕获阶段发生,false是冒泡阶段发生
outer.addEventListener("click", function () {
console.log("outer");
}, true);
inner.addEventListener("click", function () {
console.log("inner");
}, false);
点击center的div,输出:outer、inner、body
4.案例-鼠标跟随jQuery |
效果图:
HTML代码:
<div id="box" class="box">
<img src="img/1.jpg" bigImg="img/11.jpg"/>
<img src="img/2.jpg" bigImg="img/22.jpg"/>
<img src="img/3.jpg" bigImg="img/33.jpg"/>
<img src="img/4.jpg" bigImg="img/44.jpg"/>
<div id="mark">
<img src="img/11.jpg"/>
</div>
</div>
CSS代码:
body, div, ing {
margin: 0;
padding: 0;
}
img {
display: block;
border: none;
}
.box {
width: 450px;
margin: 20px auto;
position: relative;
}
.box img {
width: 100px;
border: 1px solid #777777;
float: left;
margin-left: 10px;
}
#mark {
position: absolute;
top: 0px;
left: 0;
width: 384px;
height: 216px;
border: 1px solid #5bc0de;
z-index: 10;
display: none;
}
#mark img {
border: none;
float: none;
margin-left: 0px;
width: 100%;
height: 100%;
}
JavaScript代码(jQuery):
$(function () {
var $box = $("#box"),
$mark = $("#mark"),
$boxOffset = $box.offset(); //获取当前元素距离body的偏移
$box.children("img").mouseover(function (e) {
e = e || window.event;
e.target = e.target || e.srcElement;
var left = e.clientX - $boxOffset.left + 10;
var top = e.clientY - $boxOffset.top + 10;
$mark.stop().show(100).css({left: left, top: top}).find("img").attr("src", e.target.getAttribute("bigImg"));
}).bind("mousemove", function (e) {
e = e || window.event;
e.target = e.target || e.srcElement;
var left = e.clientX - $boxOffset.left + 10;
var top = e.clientY - $boxOffset.top + 10;
$mark.css({left: left, top: top});
}).bind("mouseout", function (e) {
$mark.stop().hide(100);
});
});
5.案例-鼠标跟随JS版 |
效果图:
HTML代码:
<div id="box">
<!--<div id="mark"></div>-->
</div>
CSS代码:
body, div {
margin: 0;
padding: 0</