事件对象
案例 — div跟随鼠标移动
案例初期
HTML
<body style="height: 1000px;">
<div id= "box1"></div>
</body>
CSS
#box1{
width : 100px;
height : 100px;
background-color : red;
position : absolute;
}
Script
document.onload = function(){
var box = document.getElementById("box1");
document.onmousemove = function(event){
event = event || window.event;
var left = event.clientX;
var top = event.clientY;
box.style.left = left + "px";
box.style.top = top + "px";
}
}
event = event || window.event
在IE8中,响应函数被触发时,浏览器不会传递事件对象
在IE8及以下的浏览器中,是将事件对象作为window对象的属性来保存的clientX
和clientY
用于获取鼠标在当前的窗口的坐标
以上代码在div小于浏览器窗口的时候,才适用。然而div的偏移量应该是相对于整个页面的
pageX
和pageY
可以获取鼠标相对于当前页面的坐标
然而IE8不支持
案例修正版
-
实际滚动轴的距离+鼠标在页面当前窗口的坐标 = div的实际坐标
-
获取滚动条滚动的距离
document.body.scrollTop
- chrome认为浏览器的滚动条是body的,可以通过
body.scrollTop
来获取 - 火狐等浏览器认为浏览器的滚动条是HTML的
- HTML的滚动高度使用
documentElement.scrollTop
- chrome认为浏览器的滚动条是body的,可以通过
-
Script
修改最终版
document.onload = function(){
var box = document.getElementById("box1");
document.onmousemove = function(event){
event = event || window.event;
var left = event.clientX;
var top = event.clientY;
var st = document.body.scrollTop || document.documentElement.scrollTop;
var sl = document.body.scrollLeft || document.documentElement.scrollLeft;
box.style.left = left + st + "px";
box.style.top = top + sl + "px";
}
}
事件的冒泡Bubble
- 所谓的冒泡指的就是事件的向上传导,当后代元素上的时间被触发时,其祖先元素的相同事件也会被触发
- 在开发中大部分冒泡是有用的,如果不希望事件冒泡可以通过事件对象来取消冒泡
event.cancleBubble = true;
,以下举例无用冒泡
1.HTML
<div id="box1">
我是box1
<span id="s1">
我是span
</span>
</div>
JS
document.onload = function(){
var s1 = document.getElementById("s1");
s1.onclick = function (event) {
alert("我是span的单击函数");
event = event || window.event;
event.cancelBubble = true;
}
var box1 = document.getElementById("box1");
box1.onclick = function (event) {
alert("我是div的单击函数");
event = event || window.event;
event.cancelBubble = true;
}
document.body.onclick = function (event) {
alert("我是body的单击函数");
event = event || window.event;
event.cancelBubble = true;
}
}
事件的委派
html
<button id="btn01">添加超链接</button>
<ul id="ul">
<li><a href="javascript:;">超链接1</a></li>
<li><a href="javascript:;">超链接2</a></li>
<li><a href="javascript:;">超链接3</a></li>
</ul>
2.JS
为每一个链接绑定事件,并设置按钮,添加链接
document.onload = function(){
var allA = document.getElementById("a");
for (var i = 0; i <allA.length; i++) {
allA[i].onclick = function () {
alert("我是a的单击相应函数");
}
}
var btn = document.getElementById("btn01");
btn.onclick = function () {
var li = document.createElement("li");
li.innerHTML ="<a href='javascript:;'>新建超链接</a>";
allA.append(li);
}
}
新增的链接是不会触发点击事件的,必须重新绑定,因此我们希望绑定一次,应用到多个元素上,即使元素是后添加的。尝试将其绑定给元素的共同的祖先元素
ul.onclick = function(){
alert("我是ul的单击相应函数");
}
- 这就是事件的委派
- 指将事件统一绑定给元素的共同的族元素,这样当后代元素上的时间触发,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件
- 事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
- 如果在a链接需要制定特定的元素执行,可以使用
event.target
获取对象进行特定的判定
事件的绑定
onclick
只能存在一个,最后一个覆盖前者。
- 如果需要触发事件的时候,执行多个处理函数
- IE8及以上浏览器,使用
addEventListener
- 第一个参数:事件不用
on
- 第二个参数,回调函数
- 输出this,返回的是绑定时间的对象
- 先绑定的先执行
- 第一个参数:事件不用
- 在IE8以下可以使用
attachEvent
- 第一个参数:事件用
on
- 第二个参数,回调函数
- 输出this,返回的是window
- 后绑定的后执行
- 第一个参数:事件用
- IE8及以上浏览器,使用
- 然而在IE8以上的浏览器不认为
attachEvent
是一个方法 - 定义一个函数,用来为指定元素绑定相应函数
function bind(obj, eventStr, callBack){
if(obj,addEventListener){
//大部分浏览器兼容你的方式
obj,addEventListener(eventStr, callBack, false);
}else{
//IE8及以下
obj.attachEvent("on"+eventStr, callBack);
}
}
- 参数:
obj 要绑定的对象
eventStr 事件的字符串
callback 回调函数 - 存在的问题:this不同,说明callBack内,不好使用this
- callBack不是由我们调用的,否则可以使用
callBack.call(obj);
指定this - 解决方法:在匿名函数中,调用
callBack.call(obj);
- callBack不是由我们调用的,否则可以使用
事件绑定修正版bind
function bind(obj, eventStr, callBack){
if(obj,addEventListener){
//大部分浏览器兼容你的方式
obj,addEventListener(eventStr, callBack, false);
}else{
//IE8及以下
obj.attachEvent("on"+eventStr, function (){
callBack.call(obj);
});
}
}
事件的传播
- 关于时间的传播网景公司和微软公司有不同的理解
- 微软公司认为事件应该是由内向外传播,也就是当时间触发,应该先触发当前元素上的事件,然后再向当前元素上的祖先元素上传播,也就说时间应该在冒泡阶段执行。
- 网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,然后在向内传播给后代元素
- W3C综合了俩个公司的方案,将事件传播分为了三个阶段
- 捕获阶段
- 在补货阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默许此时不会触发事件
- 目标阶段
- 事件捕获到目标元素,捕获借书可以在目标元素上触发事件
- 冒泡阶段
- 事件从目标元素向他的祖先事件传递,依次触发祖先元素上的事件
- 捕获阶段
- 如果希望在不胡阶段剧触发事件,可以将addEventListener()的第三个参数设置为true,一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false
- IE8及以下的浏览器中没有捕获阶段
- 图解
案例二 — 鼠标拖拽div
CSS
#box1{
width:100px;
height: 100px;
position: absolute;
background-color: yellow;
}
HTML
<p>ninghao</p>
<div id="box1"></div>
JS
window.onload = function () {
var box1 = document.getElementById("box1");
box1.onmousedown = function (event) {
event = window.event || event;
var sl = event.clientX - box1.offsetLeft;
var st = event.clientY - box1.offsetTop;
box1.setCapture && box1.setCapture();
document.onmousemove = function (event) {
event = window.event || event;
var left = event.clientX - sl;
var top = event.clientY - st;
box1.style.left = left+"px";
box1.style.top = top+"px";
}
document.onmouseup = function () {
document.onmousemove = null;
document.onmouseup = null;
box1.releaseCapture && box1.releaseCapture();
}
return false;
}
}
4.代码说明
- 移动前的div与移动后的div 的偏移距离,可以使div跟随鼠标移动,而不会点击非左上角的时候,div的左上角坐标等于点击div的坐标,产生卡顿效果。
- 当我们拖拽一个网页的内容时,浏览器会默认去搜索引擎中搜索内容
- 此时会导致拖拽功能的异常,这个是浏览器的默认行为
- 如果不希望发生这个行为,可以通过
return false
来取消默认行为 - 但是这招对IE8不适用,解决方案:
setCapture()
与releaseCapture
鼠标捕获- 但是
setCapture
只有IE支持,但是在火狐调用时不会报错 - 而如果使用chrome调用时,会报错
- 但是
box1.releaseCapture
&&box1.releaseCapture();
鼠标滚动事件
onmousewheel
鼠标滚动事件,会在滚轮滚动的时候触发- 但是火狐不支持该属性
- 在火狐中需要使用
DOMMouseScroll
来绑定滚动事件- 注意:该事件需要通过addEventListener()函数来绑定
- 举例:
HTML
<div id= "box1"></div>
CSS
#box1{
width :100px;
height:100px;
position:absolute;
}
JS
var box1 = document.getElementById("box1");
box1.onmousewheel = function (event){
event = event || window.event;
//判断滚轮方向
if(event.wheelDelta > 0 || event.detail < 0){
//向上
box1.style.height = box1.clientHeight - 10 +"px";
}else{
//向下
box1.style.height = box1.clientHeight + 10 +"px";
}
};
event.peventDefault();
return false;
bind(box1,"DOMMousScroll",box1.onmousewheel );
event.wheelDelta
这个属性火狐不支持- 原因:
event.detail
火狐使用此属性来获取滚动的方向 - 结论:
if(event.wheelDelta > 0 || event.detail < 0)
判断方向
- 原因:
- 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,这是浏览器的默认行为,如果不希望发生,则可以取消默认行为。
return false
,火狐不能- 原因:火狐在使用
addEventListener()
方法绑定响应函数,取消默认行为时不能使用return false,event来取消默认行为event.preventDefault
- 结论:
event.peventDefault();
与return false;
同时使用,然而IE8不支持event.preventDefault() - 最终结论:使用
event.preventDefault && event.preventDefault()
- 原因:火狐在使用
键盘事件
- 键盘事件一般会给可以获取到焦点的对象或者是document
- 键盘事件:
- onkeydown
- 按键被按下
- 对于onkeydown来说如果一直按着某个按键不松手,则事件一直会被触发
- 连续操作在第一次操作的时候都会卡一点,这是浏览器为了防止误操作(定时器可以修改)
- onkeyup
-event.keyCode
altKey
ctrlKey
shiftKey
这个可以任意组合判断
- onkeydown
- 例如:输入框的
onkeydown
内return false
,可以阻止输入框默认行为,但是文本框输入内容为keydown的默认行为- 这样,可以限制输入框内容只能输入数字
onkeydown
连续操作控制div移动
1.HTML
<div id="box"></div>
- CSS
#box{
height:100px;
width: 100px;
background-color: yellow;
position: absolute;
}
- JS
window.onload = function(){
var box = document.getElementById("box");
document.onkeydown = function (event) {
event = event || window.event;
var speed = 10;
if(event.ctrlKey){
speed = 500;
}
switch (event.keyCode) {
case 37:
box.style.left = box.offsetLeft - speed +"px";
break;
case 38:
box.style.top = box.offsetTop - speed +"px";
break;
case 39:
box.style.left = box.offsetLeft + speed +"px";
break;
case 40:
box.style.top = box.offsetTop + speed +"px";
break;
}
}
}