十一、事件

233 阅读7分钟

1. 事件的模式

1.1 内联模式

  • 直接在标签中绑定事件(要加小括号),
  • 相对应的函数一定要是全局函数
  • this指向window

1.2 脚本模式

    1. 获取dom元素
    1. 绑定事件
    1. this指向的是当前dom元素

【注】运行顺序:

  • ① 页面dom结构渲染,遇到script标签页面停止渲染,开始加载外部资源,加载完立即执行js脚本,执行完再加载页面。
  • async:页面渲染和加载同时进行,script加载完之后立即执行js脚本,执行的过程中页面停止渲染,执行完再加载页面。async必须和script的src属性同时使用
  • defer:页面渲染和加载同时进行,页面渲染完之后再执行js脚本。defer必须和script的src属性同时使用

QQ图片20230404085413.png

2. 事件的分类

2.1 鼠标事件

  • ① 单击事件 onclick
  • ② 双击事件 ondblclick
  • ③ 鼠标按下事件 onmousedown
  • ④ 鼠标抬起事件 onmouseup
  • ⑤ 鼠标进入事件 onmouseenter
  • ⑥ 鼠标离开事件 onmouseleave
  • ⑦ 鼠标移动事件 onmousemove
  • ⑧ 鼠标进入事件 onmouseover ---> 进入子元素会再次触发
  • ⑨ 鼠标离开事件 onmouseout ---> 离开子元素会再次触发
  • ⑩ 鼠标滚轮事件 onmousewheel

2.2 键盘事件

  • ① 键盘按下事件 onkeydown
  • ② 键盘抬起事件 onkeyup
  • ③ 非功能键按下事件 onkeypress ---> 功能键:shift,ctrl,esc,delete...

2.3 html事件

  • ① 页面加载事件 window.onload ---> 页面加载完成+外部资源加载完成后,触发

      1) 页面的dom结构加载完成;
      2) 外部资源也要加载完成;
      3) 凡是带有src属性的标签,都有一个onload事件 (img,script)
    
  • ② 卸载事件 window.onunload

  • ③ 改变窗口大小事件 window.onresize ---> 为了防止刷新失效,需要加事件的触发--->window.resize();

  • ④ 文本框选中事件 onselect ---> 选中输入框的内容+松开鼠标

  • ⑤ 文本框改变内容事件 onchange ---> 内容改变后+失去焦点

  • ⑥ 文本框输入事件 oninput ---> 内容改变就触发

  • ⑦ 光标聚焦事件 onfocus

  • ⑧ 失去焦点 onblur

  • ⑨ 滚轮事件 window.onwheel

  • ⑩ 滚动条事件 window.onscroll

  • ⑪ 错误事件 window.onerror ---> 收集前端所有的错误(用于下次升级)

  • ⑫ 右击菜单事件 document.oncontextmenu ---> 需要阻止右击的默认行为(return fasle

  • ⑬ 表单提交 onsubmit ---> form表单的提交事件!!!

      1) 先触发js的onsubmit事件。(写了return false默认提交事件将不会被触发。)
      2) 再触发表单的默认提交
    
  • ⑭ 表单重置 onreset

【注】防抖和节流

  • debounce防抖:事件连续触发且间隔时间小于规定时间,只触发最后一次事件
  • throttle节流:在规定时间内只执行一次

3. 事件对象e

3.1 事件对象是什么:事件触发时会产生一条记录信息,包括点击的位置、点击的元素、触发的事件...

3.2 事件对象的兼容写法:

var e = evt || window.event

  • window.event ---> ie的写法
  • evt ---> 事件对应函数的一个形参

3.3 事件对象的常用属性:

  • e.button ---> 0 左键,1 中间键,2 右键
  • e.ctrlKey ---> 默认false,如果按下了ctrl键,就是true
  • e.shiftKey ---> 默认false,如果按下了shift键,就是true
  • e.altKey ---> 默认false,如果按下了alt键,就是true
  • e.metaKey ---> 默认false,如果按下了meta键,就是true
  • e.keyCode ---> 和onkeydown搭配使用 ---> enter 13,左 37,上 38,右 39,下 40
  • e.charCode ---> 和onkeypress搭配使用
  • e.pageX,e.pageY ---> 鼠标点的点到页面的距离
  • e.clientX,e.clientY ---> 鼠标点击的点到浏览器可视区的距离
  • e.offsetX,e.offsetY ---> 鼠标点击的点当前元素左上角的距离
  • e.screenX,e.screenY ---> 鼠标点击的点到屏幕的距离

4. offset 三大家族

4.1 offsetWidth,offsetHeight ---> 获取自身宽高(自身宽高+border+padding)

【注意】 offsetWidth,offsetHeight 和 style.width,style.height 的区别:

  1. offsetWidth,offsetHeight 用来获取自身宽高。---> 能拿到内联样式内部样式外部样式里面设置的宽高,而且不带单位,便于计算
  2. style.width,style.height 用来设置自身宽高。---> 只能获取到内联样式设置的宽高而且带单位

4.2 offsetLeft,offsetTop ---> 获取当前元素到有定位父元素之间的距离。如果父元素都没有定位,就到body的距离

4.3 offsetParent ---> 获取带有定位的父元素

5. 事件委托与目标元素 e.target

  1. 什么是事件委托:把事件绑定给父元素,通过 e.target 得到被点击的元素。
  2. 事件委托的作用:可以减少事件绑定带来的开销

6. 阻止事件冒泡

6.1 事件流:

  • 事件是有传递性的,当几个都具有事件的元素层叠在一起的时候,那么你点击其中一个元素,层叠在你点击范围的所有元素都会触发事件。捕获阶段:由外向内。冒泡阶段:由内向外。

6.2 为什么要阻止事件冒泡:

  • 当只在指定的节点上添加事件, 而不想让其传递到外层节点触发事件, 这样我们就需要阻止事件冒泡。

6.3 阻止事件冒泡的方法 ---> 通过事件对象e

  • e.stopPropagation( ); ---> google 火狐 (重点)

  • e.cancelBubble = true; ---> ie

  • 兼容写法:

          if (e.stopPropagation) { //判断e有没有这个方法,如果有调用这个方法,否则else调用另外一种方法。方法也是属性的一种,只是方法的值是一个函数。
              e.stopPropagation();  
          } else {
              e.cancelBubble = true;
          }
    

7. 阻止默认行为

7.1 默认行为

  • ① a标签的跳转
  • ② 表单的提交
  • ③ 表单的重置
  • ④ 图片的拖拽
  • ⑤ 右击菜单

7.2 阻止默认行为的方法

  • 方式一:return false;

  • 方式二:通过事件对象 e

    • e.preventDefault( ) ---> google 火狐 (重点)

    • e.returnValue = false ---> ie

    • 兼容写法:

        if (e.preventDefault) { //判断e有没有这个方法,如果有调用这个方法,否则else调用另外一种方法。方法也是属性的一种,只是方法的值是一个函数。
            e.preventDefault();  
        } else {
            e.returnValue = false;
        }
      

8. 事件监听

多次绑定事件的好处:单个事件可以实现多种功能。

oBox.onclick=fn; 不能多次绑定事件。(因为直接多次用事件绑定很容易被覆盖) ---> 多次绑定事件需要用到事件监听。

8.1 添加事件监听 oBox.addEventListener(参数1,参数2,参数3)

  • ① 参数1:事件名称(没有on)
  • ② 参数2:回调函数fn
  • ③ 参数3:布尔值 / 对象
    • 1)若是Boolean值。表示是否在捕获阶段监听。
      • 默认值是false ---> 冒泡阶段;true---> 捕获阶段
    • 2)若是对象。表示用来修饰回调函数fn的一些可选属性。{ }里面的可选值:
      • once:true, // fn执行一次就清除fn
      • capture:true, // fn在捕获阶段执行
      • passive:true, // fn永远不会调用 preventDefault( )

【了解】oBox.attachEvent("onclick",fn); // 添加事件 (ie678写法)

8.2 移除事件监听 oBox.removeEventListener("事件名称",回调函数)

【注意】添加的函数与移除的函数必须是同一个才生效。函数是引用类型,储存在堆中,不会被轻易改变。 QQ图片20230406210020.png 【了解】oBox.detachEvent("onclick",fn); // 移除事件 (ie678写法)

8.3 事件流的捕获阶段 ---> 要用事件监听

QQ图片20230406210741.png

9. 封装工具库

  • 全局函数、全局变量的缺点:容易被污染,被其他的所覆盖或者修改。
  • 解决办法:自执行函数,自运行函数,会自己运行起来。写法:(function(){})()
    • ① 第1个小括号里面放匿名函数;
    • ② 第2个小括号表示调用,可以往里面传参
  • 封装js库的格式:

QQ图片20230406210741.png

10. 一些封装的方法

10.1 随机颜色

    function randomColor() { // 16进制写法
        var str = "#";
        for (var i = 0; i < 6; i++) {
            str += parseInt(Math.random() * 16).toString(16);
        }
        return str;
    }

10.2 生成范围内的随机数

    function randomNum(n, m) {
        var max = n > m ? n : m;
        var min = n < m ? n : m;
        return parseInt(Math.random() * (max - min + 1)) + min;
    }

10.3 数组去重

    function noRepeat(arr) {
        var newArr = [];
        for (var i = 0; i < arr.length; i++) {
            if (newArr.indexOf(arr[i]) == -1) {
                newArr.push(arr[i]);
            }
        }
        return newArr;
    }

10.4 获取元素的属性值 ---> 当元素被隐藏时部分属性值获取不到,就需要用到该方法

    function getStyle(ele, attr) {
        if (window.getComputedStyle) {
            return window.getComputedStyle(ele, null)[attr];
            // window.getComputedStyle(参数1,参数2) ---> 谷歌,火狐写法
            // 参数1:指定元素
            // 参数2: ① null ---> 获取指定元素(参数1)的样式属性
            //        ② :before, :after ---> 获取指定元素的伪元素
        }
        return ele.crrentStyle[attr];
        // 指定元素.crrentStyle ---> ie写法
    }

10.5 获取元素到body的距离 ---> offsetParent最高级别是body

    function offset(ele) {
        var o = { left: ele.offsetLeft, top: ele.offsetTop };
        while (ele.offsetParent) {
            ele = ele.offsetParent;
            o.left += ele.offsetLeft;
            o.top += ele.offsetTop;
        }
        return o;
    }

10.6 获取不可见区域的高度

    function getScroll() {
        if (window.pageYOffset != undefined) { // 适用ie9,谷歌,火狐而且不用考虑DTD
            return {
                left: window.pageXOffset,
                top: window.pageYOffset,
            }
        } else if (document.compatMode == "CSS1Compat") { // 判断是否有声明头
            return {
                left: document.documentElement.scrollLeft,
                top: document.documentElement.scrollTop,
            }
        }
        return { 
            left: document.body.scrollLeft,// 适用 ie 6 7 8
            top: document.body.scrollTop,
        }
    }