zoukankan      html  css  js  c++  java
  • 前端笔记之JavaScript(十一)event&BOM&鼠标/盒子位置&拖拽/滚轮

    一、事件对象event

    1.1 preventdefault()returnValue阻止默认事件

    通知浏览器不要执行与事件关联的默认动作。

    preventdefault()  支持Chrome等高级浏览器

    returnValue     支持IE678

    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       支持IE678

    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


    三、鼠标位置

    当我们给某一个盒子添加鼠标事件监听时(clickmouseovermouseentermouseout等事件),都一定会有以下四组值:

     event.pageX         event.pageY

     event.screenX       event.screenY

     event.clientX       event.clientY

     event.offsetX       event.offsetY

    event.pageY    表示鼠标指针,到页面顶端的距离。IE678不兼容

    event.screenY  表示鼠标指针,到屏幕顶端的距离

    event.clientY  表示鼠标指针,到视口顶端的距离(视口就是当前可视窗口)

    event.offsetY  表示鼠标指针,到盒子顶端的距离

    规律:

    1、当页面没有卷动的时候,pageY一定等价于clientY。或换句话说pageY等价于clientY+页面卷动的值scrollTop

    2IE678不兼容pageXpageY

    3offsetX/Y会被儿子影响。

    offsetX/Y指的不是距离你监听的那个盒子左上角的距离,而是指的你现在鼠标指针所在位置到此时最内层盒子左上角的距离。

     


    四、盒子位置

    任何一个元素都有offsetParent属性,和offsetLeftoffsetTop属性

     


    4.1计算盒子在页面中的净位置

    现在我们就可以用offsetParentoffsetTop/Left计算一个元素的净位置了,是一个迭代的过程。

    xiaoming的净位置:xiaoming.offsetTop + xiaoming.offsetParentxiaoming.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低版本不兼容pageXpageY,所以用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在容器中拖拽

    图片在父级容器中拖拽的时候,不仅仅是给图片加了一个限制区域,图片的topleft参考点是父盒子左上角,鼠标指针的位置点就不一致。图片的topleft起点是A,而鼠标指针clinetXY参考点是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,比例一定要相同,如果比例不相同,放大镜放大感觉就不一样了,无法看全。


    六、鼠标滚轮事件

    页面中经常有鼠标滚轮事件,比如做一个内置有纵向滚动条的盒子

    ChromeIE各个版本浏览器都支持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


  • 相关阅读:
    java中高级软件工程师面试总结
    失败的面试经历
    解决webstorm打开包含node_modules项目卡死问题
    通俗易懂的理解javascript闭包
    javascript实现silverlight pivotViewer控件
    javascript面向对象
    吐槽一下万网空间
    html5的Canvas
    前端CSS兼容的一些思路
    Win10 Ubuntu子系统访问Windows目录
  • 原文地址:https://www.cnblogs.com/rope/p/10610260.html
Copyright © 2011-2022 走看看