前端笔记知识点整合之JavaScript(十一)event&BOM&鼠标/盒子位置&拖拽/滚轮
一、事件对象event
1.1 preventdefault()和returnvalue阻止默认事件
通知浏览器不要执行与事件关联的默认动作。
preventdefault() 支持chrome等高级浏览器
returnvalue 支持ie6、7、8
var box = document.getelementbyid('box'); var i = 0; //鼠标在box盒子滚动时触发 box.onmousewheel = function(event){ var event = event || window.event; //能力检测,阻止默认事件 if(event.preventdefault){ event.preventdefault(); }else{ event.returnvalue = true; } this.innerhtml = '你在我身上滚动了!' + i++; }
1.2 stoppropagation()和cancelbubble阻止事件继续传播
stoppropagation() 支持chrome等高级浏览器
cancelbubble 支持ie6、7、8
var box1 = document.getelementbyid('box1'); var box2 = document.getelementbyid('box2'); var box3 = document.getelementbyid('box3'); box1.onclick = function(){ alert('box1'); } box2.onclick = function(event){ alert('box2'); //阻止事件继续传播,能力检测 if(event.stoppropagation){ event.stoppropagation(); }else{ event.cancelbubble = true; } } box3.onclick = function(){ alert('box3'); }
二、bom
浏览器对象模型(browser object model)
2.1卷动事件
当窗口无论向上向下卷动的时候,比如键盘↓了,滚动鼠标滚轮,拖拽滚动条,都会触发这个事件。
window.onscroll=function(){ }
2.2窗口的宽度和高度
认识一个对象:
document.documentelement |
就是页面document,想要得到窗口的宽度和高度,不是window对象,而是document对象,所以:
document.documentelement.clientwidth document.documentelement.clientheight |
但是去掉页面dtd,或ie678浏览器中,把下面的语句当做浏览器窗口的宽度和高度
document.body.clientwidth document.body.clientwidth |
所以兼容语法:
document.documentelement.clientwidth || document.body.clientwidth; document.documentelement.clientheight || document.body.clientwidth; |
2.3窗口的卷动值
兼容语法:
document.documentelement.scrolltop || document.body.scrolltop |
兼容所有浏览器
document.documentelement.scrolltop |
兼容不写dtd的情况下:
document.body.scrolltop |
三、鼠标位置
当我们给某一个盒子添加鼠标事件监听时(click、mouseover、mouseenter、mouseout等事件),都一定会有以下四组值:
event.pagex event.pagey event.screenx event.screeny event.clientx event.clienty event.offsetx event.offsety |
event.pagey 表示鼠标指针,到页面顶端的距离。ie6、7、8不兼容
event.screeny 表示鼠标指针,到屏幕顶端的距离
event.clienty 表示鼠标指针,到视口顶端的距离(视口就是当前可视窗口)
event.offsety 表示鼠标指针,到盒子顶端的距离
规律:
1、当页面没有卷动的时候,pagey一定等价于clienty。或换句话说pagey等价于clienty+页面卷动的值scrolltop。
2、ie678不兼容pagex、pagey
3、offsetx/y会被儿子影响。
offsetx/y指的不是距离你监听的那个盒子左上角的距离,而是指的你现在鼠标指针所在位置到此时最内层盒子左上角的距离。
四、盒子位置
任何一个元素都有offsetparent属性,和offsetleft、offsettop属性
4.1计算盒子在页面中的净位置
现在我们就可以用offsetparent和offsettop/left计算一个元素的净位置了,是一个迭代的过程。
xiaoming的净位置:xiaoming.offsettop + xiaoming.offsetparent的xiaoming.offsetparent.bordertop ...
由于ie8很特殊,所以我们迫切的需要知道浏览器是不是ie8。所以使用:
window.navigator.useragent
来检测浏览器的版本。
|
|
var ie8 = window.navigator.useragent.indexof("msie 8.0") != -1; |
下面的函数就是得到一个元素在页面上的总净位置:
function offset(o){ //初始值 var result = { "top" : o.offsettop, "left" : o.offsetleft } //判断浏览器是不是ie8 var isie8 = window.navigator.useragent.indexof("msie 8.0") != -1; //循环迭代,寻找父亲 while(o = o.offsetparent){ //计算后的边框的值 if(window.getcomputedstyle){ var bordertop = parseint(getcomputedstyle(o)['border-top-width']); var borderleft = parseint(getcomputedstyle(o)['border-left-width']); }else{ var bordertop = parseint(o.currentstyle['bordertopwidth']); var borderleft = parseint(o.currentstyle['borderleftwidth']); } //验证一下,万一bordertop是undefined或nan,此时修正为0 if(isnan(bordertop)){ bordertop = 0; } if(isnan(borderleft)){ borderleft = 0; } //如果浏览器版本不是ie8那么就加上边框,如果是ie8就不需要加边框,抛出自己 !isie8 && (result.top += bordertop); !isie8 && (result.left += borderleft); result.top += o.offsettop; result.left += o.offsetleft; } return result; }
4.2曲线救国得到鼠标在盒子中的位置:
var box = document.getelementbyid("box"); var result = document.getelementbyid("result"); //监听父亲鼠标移动的时候,鼠标指针的offsetx值和offsety值 box.onmousemove = function(event){ var event = event || window.event; var x = event.pagex - getalloffset(box).left; var y = event.pagey - getalloffset(box).top; result.innerhtml = x + "," + y; }
由于ie低版本不兼容pagex和pagey,所以用clientx/y加上卷动值:
var box = document.getelementbyid("box"); var result = document.getelementbyid("result"); //监听父亲鼠标移动的时候,鼠标指针的offsetx值和offsety值 box.onmousemove = function(event){ var event = event || window.event; //曲线救国!!!!得到窗口卷动的值 var scrolltop = document.documentelement.scrolltop || document.body.scrolltop; var scrollleft = document.documentelement.scrollleft || document.body.scrollleft; //鼠标的offsetx、offsety等于视口的值,加上卷动值减去净位置。 var x = event.clientx + scrolltop - getalloffset(box).left; var y = event.clienty + scrollleft - getalloffset(box).top; result.innerhtml = x + "," + y; }
五、拖拽
5.1 在页面上拖拽
页面上的元素,能够被鼠标拖拽。整体思路:
① 当鼠标在img上按下去的时候,注册document的鼠标移动事件监听;反之,当鼠标在屏幕任何位置抬起的时候,剥夺document的鼠标移动事件监听。
② 为了让鼠标能够一直按住图片的同一个位置,所以要在mousedown的一瞬间记录误差(见下图)。
var img = document.getelementsbytagname('img')[0]; //鼠标指针在图片上按下的时候 img.onmousedown = function(event){ var event = event || window.event; //记录误差,目的是当我按住baby的脑门子拖拽的时候,鼠标指针一直在脑门子上。 var dx = event.offsetx; var dy = event.offsety; //注册新的事件 //在document上移动的时候,让img跟随鼠标 document.onmousemove = function(event){ var event = event || window.event; //移动的时候top值等于当前的鼠标指针位置减去开始的时候的误差 var x = event.clientx - dx; var y = event.clienty - dy; img.style.left = x + "px"; img.style.top = y + "px"; //这个return false可以解决ie8的内置事件 return false; } //这个return false可以解决ie8的内置事件 return false; } //鼠标指针在任何位置抬起的时候,删除document上的move监听 document.onmouseup = function(){ document.onmousemove = null; }
5.2在容器中拖拽
图片在父级容器中拖拽的时候,不仅仅是给图片加了一个限制区域,图片的top、left参考点是父盒子左上角,鼠标指针的位置点就不一致。图片的top、left起点是a,而鼠标指针clinetx、y参考点是b点。
大家参考点就不一样了。
方法:只要把它们的坐标统一就可以了,所以我们需要得到鼠标指针相对于盒子的坐标位置,此时需要使用曲线救国,因为offsetx/y会被儿子影响。
var img = document.getelementsbytagname('img')[0]; var box = document.getelementbyid('box'); //得到盒子的净位置 var boxoft = offset(box).top; var boxofl = offset(box).left; console.log(boxoft,boxofl) //鼠标指针在图片上按下的时候 img.onmousedown = function(event){ var event = event || window.event; //记录误差,目的是让我按住baby的脑门拖拽的时候,鼠标指针一直在脑门上 var dx = event.offsetx; var dy = event.offsety; //鼠标按下,然后执行鼠标移动时间,接着在document上移动,让img跟着移动 document.onmousemove = function(event){ var event = event || window.event; //曲线救国!!!!得到窗口卷动的值 var scrolltop = document.documentelement.scrolltop || document.body.scrolltop; var scrollleft = document.documentelement.scrollleft|| document.body.scrollleft; //鼠标的offsetx、offsety等于视口的值,加上卷动值减去净位置 //移动的时候top值等价于鼠标指针位置减去开始按下的误差 var x = event.clientx + scrollleft - boxofl - dx; var y = event.clienty + scrolltop- boxoft - dy; console.log(x,y) //验收 if(x > 300){ x = 300; }else if(x < 0){ x = 0; } if(y > 300){ y = 300; }else if(y < 0){ y = 0; } img.style.left = x+'px'; img.style.top = y+'px'; //这个return false可以解决浏览器内置事件 return false; } } //在鼠标指针任何位置抬起的时候,移除document上的move事件监听 document.onmouseup = function(){ document.onmousemove = null; }
5.3放大镜效果
和刚刚的拖拽不一样,鼠标指针不需要按下了,所以逻辑变得简单了。
放大镜的放大原理:不是真的放大,只是当左边小放大镜移动的时候,右边的大图按比例移动,形成放大的感觉。
比例问题:
小图盒子350宽高,放大镜175宽高
大图盒子400宽高,图片800宽高
这里暗含了两个1:2,比例一定要相同,如果比例不相同,放大镜放大感觉就不一样了,无法看全。
六、鼠标滚轮事件
页面中经常有鼠标滚轮事件,比如做一个内置有纵向滚动条的盒子
chrome和ie各个版本浏览器都支持onmousewheel事件,表示鼠标滚轮滚动的时候触发,火狐不支持这个事件,它支持的是自己的dommousescroll事件,我们不需要进行能力检测,因为所有的浏览器遇见别人添加监听的方法都不报错(静默)。
var box = document.getelementbyid('box'); //除了火狐浏览器之外,都支持以下这种监听滚轮事件 box.onmousewheel = mousewheel; //火狐独有的,必须用dom2级添加监听 box.addeventlistener('dommousescroll',mousewheel,true); //事件处理函数 function mousewheel(){ alert('滚动了!!!'); }
鼠标滚轮事件的event对象有属性wheeldelta,火狐是detail属性,可以反映你的滚轮方向和力度
非火狐向上120(力度越大数字越大),火狐向上是-3
非火狐向下-120(力度越大数字越大),火狐向上是3
所以要进行兼容性处理,把它们的值统一为:1和-1
box.onmousewheel = mousewheel; //火狐独有的,必须用dom2级添加监听 box.addeventlistener('dommousescroll',mousewheel,true); //事件处理函数 function mousewheel(event){ //进行方向的能力检测,由于火狐和大家不一样,用if分开判断 if(event.wheeldelta){ //非火狐 // if(event.wheeldelta > 0){ // var direction = 1; // }else{ // var direction = -1; // } var direction = event.wheeldelta > 0 ? 1 : -1; }else{ //火狐 // if(event.detail > 0){ // var direction = -1; // }else{ // var direction = 1; // } var direction = event.detail > 0 ? -1 : 1; } console.log(direction) }
上一篇文章dom2级小测试的正确答案:efghibcd
解释:
1、dom0级只能添加到冒泡阶段
2、dom0级事件同名的会覆盖
3、true表示捕获,false表示冒泡,先捕获,后冒泡
4、dom2级的不会覆盖,先写的先执行
5、dom2级最内层的不区分冒泡和捕获,谁先写谁执行,无论是dom0还是dom2。
ps:尽量让它越来越规范,前期的文章都是本人的学习时的笔记整理,希望看完后可以指点一二,提提意见多多交流;
笔记流程:html>css>javascript>jquery>html5/css3>移动端>ajax>面向对象>canvas>nodejs>es678>vue>react>小程序>面试问题
意见请留言,邮箱:scarf666@163.com