Web-API-03:事件监听器

1 事件监听器

addEventListener(type, listener[, options|useCapture])
  • type 表示时间名称 用字符串表示,并且不需要在前面加on
  • listener 表示要执行的函数
  • 最后一个参数默认为false ,true 为捕获执行

事件监听与事件绑定的区别

事件绑定类似于样式覆盖,只会绑定最后的事件
而同一个元素的事件监听按照从上到下按照顺序执行,有多少执行多少
在这里插入图片描述

事件流

事件冒泡

父级子级都绑定了监听器后,点击子级,从内到外依次执行,父级监听器也会执行
在这里插入图片描述

阻止事件冒泡
e.stopPropagation();

把这句话加载事件中,就只会执行该元素的监听事件了

事件捕获

第三个参数为true时控制事件捕获,点击子级,而父级的事件将会提前执行,改变了优先级
在这里插入图片描述
在这里插入图片描述

事件监听相关配置

  • capture 是否在捕获阶段执行,首先执行捕获的事件(父级)

        var fa = document.querySelector('.father');
        var son = document.querySelector('.son');
    
        fa.addEventListener('click', function (e) {
            console.log('1');
        }, {
            capture: true,
        })
        son.addEventListener('click', function (e) {
            console.log('2');
        })
    
  • once 是否只执行一次,为true执行一次后销毁该事件

  • passive: true 阻止清除默认事件的行为,比如之后的开发想要取消默认事件的话,就无法取消了

取消监听事件 removeEventListener

需要取消的是被绑定元素上的监听事件执行的有名函数(匿名函数无法被取消事件)

    fn = function() {
        console.log('father')
    }

    fa.addEventListener('click', fn);
    fa.removeEventListener('click', fn);

2 Event事件对象

event将会以参数形式传递给事件函数

事件源

  • event.target 获取触发事件的元素 可以理解为点击的是谁就是谁
  • event.currentTarget 指的是当前处理该事件的元素、文档或窗口

点击子级
在这里插入图片描述

事件委托(事件代理)

例如留言板的删除功能,当无留言的时候,就无法获取到留言板中的删除按钮
这个时候给留言板的父级加上事件监听,只要点击到了删除的事件源,就执行删除功能

      list.addEventListener('click', function (e) {
          // console.log(1)
          console.log(e.target.tagName)
          // 事件委托/事件代理
          if (e.target.tagName == 'A') {
              var li = e.target.parentNode;
              // console.log(li);
              li.remove();
          }
      })
  })();
  • 事件委托的优点
    1. 可减少需要添加事件绑定的元素
    2. 给新增DOM元素添加事件(在不刷新页面的情况下)
  • 事件委托的缺点
    1. 事件处理函数中需要判断事件源增加逻辑复杂度
    2. 祖父级和事件源之间不能有阻止冒泡

3 常用事件

3.1 清除元素默认事件e.preventDefault();

例如鼠标右键菜单
还有a标签的跳转

3.2 鼠标移入移出事件

这俩个事件 不会在鼠标移动父子级切换过程中触发

  • mousenter
  • mouseleave 事件

区别

  • mouseover mouseout 作用于同一平面
    简单理解就是只要离开了父级平面触点(子级没有覆盖到父级的区域),父级事件就消失了
    在这里插入图片描述
  • mousenter mouseleave 作用于同一空间
    通俗来讲就是只要鼠标还在父级范围内(包括子级,子级也属于父级),就会一直保持事件
    在这里插入图片描述

鼠标的位置坐标

  • Event.clientX、Event.clientY 相对于window窗口的坐标
  • Event.pageX、Event.pageY 相对于整个元素面的坐标

案例:鼠标拖拽的实现

思路:

  1. 按下时记录此时鼠标位置坐标
  2. 拖动时记录拖动的距离

案例2:放大镜效果

要点:

  1. mask移动的距离 / mask最大能够移动的距离 = 大图片移动的距离 / 大图片最大能够移动的距离
  2. 图片应该放大的大小 mask的半径 / 显示图片的盒子的半径

3.3 鼠标右键菜单事件 contextmenu

<script>
    // contextmenu  鼠标右键事件
    window.addEventListener('contextmenu',function(e){
        console.log('鼠标右键')

        // 清除浏览器默认行为
        e.preventDefault();
    })
</script>

3.4 键盘事件

  • keydown、keyup 键盘按下,键盘弹起的事件
    • Event.keyCode、Event.key 键盘对应的ASCII码,键盘对应字符
    • keypress:按下某个键盘键并释放时触发。如果按住某个键会不断触发该事件。该事件处理函数返回 false 时,会取消默认的动作(如输入的键盘字符)。
    • Event.altKey、Event.ctrlKey、shiftKey 按下对应键位返回true,否则false
    • 制作组合键
        window.addEventListener('keydown', function(e) {
            console.log(e.key, e.keyCode);
            if (e.ctrlKey) {
                if (e.key == 'c') console.log('复制了');
                if (e.key == 'v') console.log('粘贴了');
            }
        })
    

案例:键盘控制div移动

要考虑的问题:
键盘长按其实是多次执行按下事件,但是有延迟,所以方法不可行

  • 解决办法,只执行一次按下键位,然后执行定时器,抬起键位后清除定时器
  • 难点,如何使同一个键位只按下一次?
    利用boolean数组判断某个键位是否已经按下(设置为true),然后抬起的时候再使对应键位为false(未按下)
        var box = document.querySelector('.box');
        var fa = document.querySelector('.fa');
        var x = 0;
        var y = 0;
        var keys = []; // 用于存储是否按下键位false/true

        window.addEventListener('keydown', function (e) {
            // 相同的事件只需要按下一次
            if (keys[parseInt(e.keyCode)]) return;
            console.log(x, y, parseInt(e.keyCode))
            keys[parseInt(e.keyCode)] = true;
            var timer = setInterval(move, 40)

            function move() {
                switch (e.keyCode) {
                    case 37:
                        x -= 10;
                        break;
                    case 38:

                        y -= 10;
                        break;
                    case 39:

                        x += 10;
                        break;
                    case 40:
                        y += 10;
                        break;
                }
                // 判断边界
                if (x < 0) x = 0;
                if (x > fa.clientWidth - box.offsetWidth) {
                    x = fa.clientWidth - box.offsetWidth;
                }
                if (y < 0) y = 0;
                if (y > fa.clientHeight - box.offsetHeight) {
                    y = fa.clientHeight - box.offsetHeight;
                }

                // 改变
                box.style.left = x + 'px';
                box.style.top = y + 'px';
            }

            window.addEventListener('keyup', function (e) {
                // 释放后再使键盘按下次数变为false,方便下一次按下事件
                keys[e.keyCode] = false;
                clearInterval(timer);
            })
        })

3.5 鼠标滚轮事件

  • mousewheel 用于谷歌浏览器
    e.wheelDelta 事件对象里上滚和下滚的数值
    在这里插入图片描述
  • DOMMouseScroll 用于火狐浏览器
    e.detail 火狐中获取上滚下滚的数值
    在这里插入图片描述

兼容性封装

判断当前浏览器有没有对应滚动事件即可

    // 传入操作的对象以及上下滚动触发的对应事件
    mouseWheel(window, function(){
        console.log('下')
    }, function() {
        console.log('上')
    })

    function mouseWheel(obj, downFn, upFun) {
        // 火狐事件
        obj.addEventListener('DOMMouseScroll', function (e) {
            if (e.detail < 0) {
                upFun && upFun.call(obj);
            } else {
                downFn && downFn();
            }
        })

        // Chrome事件
        obj.addEventListener('mousewheel', function (e) {
            if (e.wheelDelta > 0) {
                upFun && upFun();
            } else {
                downFn && downFn();
            }
        })
    }

案例 自定义滚动条

3.6 其他事件

  1. dbclick 双击鼠标触发
  2. focus 获得焦点时触发,例如input
  3. blur 取消焦点时触发
  4. change 值改变时,一般用于单选和复选框
  5. submit reset 提交和重置时,这个用的少

表单其他方法
el.blur() 失去焦点
el.focus() 获得焦点
el.select() 选中

4 案例

碰撞检测

在这里插入图片描述

        function isTouch() {
            var rect1 = box.getBoundingClientRect();
            var l1 = rect1.left;
            var t1 = rect1.top;
            var r1 = rect1.right;
            var b1 = rect1.bottom;

            var rect2 = box2.getBoundingClientRect();
            var l2 = rect2.left;
            var t2 = rect2.top;
            var r2 = rect2.right;
            var b2 = rect2.bottom;

            return (r1 > l2 && b1 > t2 && t1 < b2 && l1 < r2);
        }

框选

这是一个碰撞检测 + 拖拽选框的案例
难点

  1. 选框的方向
  2. 碰撞检测多个目标
 window.addEventListener('mousemove', move);

            function move(e) {
                // width height 不能有负值
                var x = Math.abs(e.clientX - downX);
                var y = Math.abs(e.clientY - downY);
                // 鼠标点击后,如果移动的方向为正方向,那么就拿downXY表示框选的位置
                // 但是如果是负方向,那么框选的位置就是个不定数,需要跟着鼠标移动
                var left = Math.min(downX, e.clientX);
                var top = Math.min(downY, e.clientY);
                box.style.left = left + 'px';
                box.style.top = top + 'px';
                box.style.width = x + 'px';
                box.style.height = y + 'px';

                boxs.forEach(function (item, index) {
                    if (isTouch(box, item)) {
                        item.classList.add('active');
                    } else {
                        item.classList.remove('active');
                    }
                })


            }

            window.addEventListener('mouseup', function () {
                window.removeEventListener('mousemove', move);
                box.remove();
                var selects = document.querySelectorAll('.active');
                Array.from(selects);
                selects.forEach(function (item) {
                    box2.appendChild(item);
                    item.classList.remove('active');
                })
            }, {
                once: true,
            })

圆形碰撞检测

难点

  1. 两点间距离公式,勾股定理

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值