【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件

❤️ Author: 老九
☕️ 个人博客:老九的CSDN博客
个人名言:不可控之事 乐观面对
系列专栏:

文章目录

  • script标签
  • DOM
  • 文档树
    • DOM指针
    • DOM属性总结
    • 查找函数实现方法
  • 获取DOM结点尺寸和位置
  • 事件处理
    • 事件处理器
    • 事件对象
      • 事件冒泡
    • 事件捕获
    • 默认行为
    • 被动事件和主动事件
    • 滚动事件

script标签

【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第1张图片

  • 注意script标签,要么写src,里面不要写内容,要么就里面写内容,不要写src,上面图片的写法是错误的

DOM

  • Document Object Model,文档对象模型,浏览器拿到html代码之后,会将这个html的代码解析成dom树,每遇到一个标签,都会为其创建一个对象,运行的时候是操作或者读取dom树,它就像一个实时的数据结构,只要是修改了dom树,对象嵌套的结构就会改变,页面展示也会改变。
  • DOM树的根节点,就放在了document这个对象上面
  • 我们可以想象html是一些嵌套的盒子,标签可以嵌套标签,盒子可以嵌套盒子。
  • document对象,就表示整个文档,展示的和面板是一样的,这个是页面创建的时候就创建了这个对象,注意和documentElement区分。
  • document.documentElement,这个是遇到html标签了之后,创建这个对象的这个属性
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第2张图片
  • 注意我们的标签的属性,和对应的dom对象的属性这是两回事,如果想看dom对象属性,通过console.dir(document.documentElement)可以看到,里面包含滚动位置,内容,标题等等一系列内容。
  • 想看documentElement的第一个子节点,可以用firstElementChild属性
    在这里插入图片描述
  • 通过children数组获取对应的dom树上的标签
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第3张图片
  • 当你在面板中选中一个对象,就会创建一个全局对象$0,后面有一个==$0,我们可以通过$0获取对应的对象
    在这里插入图片描述

文档树

  • 语法树只是把源代码所有信息解析出来,DOM树远远不止源代码的信息
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第4张图片
  • 这个是语法树,可以看到远远小于DOM树的属性值的。
  • 每一个dom结点都包含一个nodeType属性,这个是一个数字,表明它的类型,标签类型是1,文本类型是3,注释结点的nodeType是8
  • DOM对象有一个childNodes的属性,这个属性指向一个类数组对象,有一个length属性,里面存的是该元素包含的子节点;childNodes属性包含文本节点,children属性不包含文本节点
    在这里插入图片描述
  • 下面高光的就是text文本节点。

【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第5张图片

  • 如果创建标签
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第6张图片
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第7张图片
  • 这样创建是非常繁琐的,这时候就出现了一些库,最有名的就是jQuery,解决DOM代码的繁琐问题。
  • JQuery是封装了DOM,Lodash是封装了js的函数,这两个要区分开 。

DOM指针

  • DOM结点包含了大量的指针指向周围的结点。
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第8张图片
  • 最后那个是lastchild指向最后一个元素。
  • 下图是firstChild和firstElementChild的区别
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第9张图片
  • 下面是previousSibling和previousElementSibling的区别。

【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第10张图片

  • 我们理论上可以利用这些属性,移动页面上的任何节点;下面这段代码可以判断我们的页面里的文本节点中有没有对应的字符串
DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Documenttitle>
    <script>
      function talksAbout(node, string) {
        if (node.nodeType == document.ELEMENT_NODE) {
          for (var child of node.childNodes) {
            if (talksAbout(child, string)) {
              return true;
            }
          }
        } else if (node.nodeType == document.TEXT_NODE) {
          return node.nodeValue.includes(string);
        }
        return false;
      }
    script>
  head>
  <body>
    <div>bbbdiv>
    <script>
      document.body.firstChild.nextSibling.nextSibling.nextSibling.textContent =
        "ccc";
    script>
    <strong>cccstrong>
    <input type="text" />
    ccc
  body>
html>

  • 这种的编码方式叫做硬编码,这种编码方式有个坏处,就是如果你改变了代码的结构,整个都需要修改,这样是非常麻烦的。
  • 通过getElementsByClassName方法,可以通过类名找到对应的结点;getElementById,getElementByName,getElementByTagName同理。
    在这里插入图片描述
  • 注意这些get方法都是返回的一个类数组对象,不能直接调用append等方法
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第11张图片
  • 如果想获得具体标签的样子,需要想数组一样取类数组对象里面的值
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第12张图片
  • 这里id属性要说明一下,如果我们定义过和id属性值一样的变量,那就用我们定义的变量,如果我们没有创建过和id属性值一样的变量,那么浏览器就会帮我们创建一个和id属性值一样的全局变量
  • append,replace系列操作,用来修改dom结构:
    在这里插入图片描述
    在这里插入图片描述
  • insertBefore前面的参数是要移动的结点,后面的是要移动到的结点 前面的结点。这个后面参数的结点必须是写在insertBefore方法前面的结点的子节点才可以(图中,参数的结点应该是body的子节点才可以)

【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第13张图片

  • 注意,在DOM中,一个结点在文档中只能出现一次,不能在两个地方同时出现,比如下面的图片所示,他虽然循环了10次,但是只能产生一个p标签,如果像创建十个,就把那个var p = document.createElement(‘p’)放在for循环里面,这样每次循环都创建一个新的p标签啦
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第14张图片

调试小技巧:如果想在控制台找到一个函数,先在console中输入这个函数,然后点击一下这个函数输出的东西,就可以自动跳转到当前函数了
在这里插入图片描述
在这里插入图片描述

  • 注意我们获取的getElementsByTagName等等,这种获取的集合是动态的集合,下面这段代码我们想把所有的img图片变成文字节点,但是我们下面这种写法只能改变第一个,改变完之后,imgs就动态改变了。
  • 如果我们要解决这个问题,我们需要倒叙遍历才可以,或者我们把一个类数组对象变成一个数组,然后使用for of循环也可以实现。在这里插入图片描述
DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Documenttitle>
  head>
  <body>
    <p>
      the cat
      <img src="cat.jpg" alt="Cat" />
      is run after the
      <img src="hat.jpg" alt="Hat" />
    p>
    <button onclick="replaceImages()">Replacebutton>
    <script>
      function replaceImages() {
        var imgs = document.getElementsByTagName("img");
        for (var i = 0; i < imgs.length; i++) {
          var img = imgs[i];
          var textNode = document.createTextNode(img.alt);
          img.parentNode.replaceChild(textNode, img);
        }
      }
    script>
  body>
html>

介绍稀疏数组,当数组里面存在下标不存在的数组,就叫做稀疏数组【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第15张图片
当我们创建 a = new Array(100000000)的时候,如果一个数组项存一个整数,一个整数占4个字节,那就要占4亿个字节,先除一个1024变成k,再除1024变成兆(M),最后算出来占381兆左右,但是在js中是不会占用这么多空间的,js会把它想成一个对象,以一个对象的形式存储,这个对象就有一个length属性。
【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第16张图片
因此我们可以得出一个结论,一个对象也可以看作是一个数组,称为类数组。
那么如果想让类数组获得数组本身的一些方法的话,我们可以通过Array.prototype.reverse.call(obj),实现this的转移,或者直接将obj._ proto _ = Array.prototype,直接将数组的原型属性赋给obj的原型上面,使得类数组获得数组的自有方法。
上面那个必须是类数组对象,才能使用reverse()

  • 下面这个函数可以实现创建嵌套标签
      function elt(tagName, ...children) {
        var node = document.createElement(tagName);
        for (var child of children) {
        //如果child是文本结点,需要判断把字符串转化成文本节点
          if (typeof child === "string") {
            child = document.createTextNode(child);
          }
          node.appendChild(child);
        }
        return node;
      }

在这里插入图片描述

  • 我们还可以对DOM结点的属性进行操作
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第17张图片
      function elt(tagName, attrs = {}, ...children) {
        var node = document.createElement(tagName);
        if (attrs) {
          for (var key in attrs) {
            debugger;
            var val = attrs[key];
            node.setAttribute(key, val);
          }
        }
        for (var child of children) {
          if (typeof child === "string") {
            child = document.createTextNode(child);
          }
          node.appendChild(child);
        }
        return node;
      }

DOM属性总结

  • 元素的查找:
    getElements?.*()
  • 元素的周围指针
    el.firstChild/lastChild/nextSibiling/previousSibiling
    el.parentNode/parentElement

parentNode和parentElement的区别
1.获取根节点的区别:parentNode 可以获取根节点,而 parentElement 获取不到根节点。如果当前节点的父节点是文档的根节点(即 Document 对象),那么 parentNode 返回该根节点,而 parentElement 返回 null。
2.获取父节点类型的区别:parentNode 可以获取任何类型的父节点,包括元素节点、文本节点、注释节点等,而 parentElement 只能获取元素节点类型的父节点,如果当前节点的父节点不是元素节点,则 parentElement 返回 null。

el.firstElementChild/lastElementChild
el.nextElementSibiling/previousElementSibiling
el.childNodes/children

  • 元素的常用方法:
    对结点进行增删改
    el.appendChild(node)
    el.removeChild(node)
    el.replaceChild(node,baseNode)
    el.insertBefore(node,baseNode)
  • 属性和操作
    node.xxxx,标准属性大都可以使用node.prop的形式访问,如id,title,alt,src,href,type,name,value,class要用className,label的for属性要用htmlFor,如果一个标签对应多个类名,我们通过node.classList.add/remove/contains/replace/toggle(切换功能,有的话就加上,没有的话就删掉)可以操作多个class类名
    node.getAttribute()/setAttribute()/removeAttribute()/hasAttribute(),这个可以访问到html的属性
    通过dataset可以获得以data-开头的自己定义的属性的值,如果有-的话会自动转成驼峰式
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第18张图片
    el.remove() 删除元素自身,就不用再写成el.parentElement.removeChild(el)
    el.replaceWith(targetNode)用targetNode替换el
    el.append(string,node,node,string…)
    el.style.xxxxx,例$0.style.fontSize=‘28px’,要写成驼峰式
    $0.innerHTML = ‘< strong >aaa< i >bbb’,这个可以直接添加一段html代码
    $0.innerText,这个可以获得去掉标签剩下的文本
    $0.textContent 元素内部的文本结点的值按顺序拼接得到的内容

查找函数实现方法

  • 遍历DOM结点,类似二叉树的先序遍历
      function traverseDOM(node, action = console.log) {
        if (node.nodeType == document.ELEMENT_NODE) {
          action(node);
          for (var child of node.children) {
            traverseDOM(child, action);
          }
        }
      }
      function traverse(root) {
        if (root) {
          console.log(root);
          traverse(root.left);
          traverse(root.right);
        }
      }
  • 实现getElementsByTagName
      function getElementsByTagName(node, tagName) {
        var result = [];
        for (var child of node.children) {
          if (child.tagName == tagName) {
            result.push(child);
          }
          result.push(...getElementsByTagName(child, tagName));
        }
        return result;
      }
      function getElementsByTagName2(node, tagName) {
        var result = [];
        traverseDOM(node, (it) => {
          if (it.tagName == tagName) {
            result.push(it);
          }
        });
        if (result[0] == node) {
          result.shift();
        }
        return result;
      }
  • 实现getElementById
      function getElementById(id, node = document.documentElement) {
        if (node.id === id) {
          return node;
        } else {
          for (var child of node.children) {
            var result = getElementById(id, child);
            if (result) {
              return result;
            }
          }
          return null;
        }
      }
       function getElementById2(id) {
        var result = null;
        traverseDOM(document.documentElement, (it) => {
          if (it.id === id) {
            result = it;
          }
        });
        return result;
      }

获取DOM结点尺寸和位置

  • 通过$0.offsetWidth和$0.offsetHeight可以获取结点的宽高,包含边框及以内的区域

  • 通过getBoundingClientRect()方法,可以获得一个元素的位置
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第19张图片

  • 页面的滚动位置:scrollX,scrollY,我们可以通过window.scrollX/scrollY/scrollTo/scrollBy(0,150):每次都向下滚动150px

补充:色块是不受行高的影响的,只是受最初行高和字号影响的。

  • 通常情况下,当元素的布局信息发生变化时,浏览器会立即重新计算并更新 clientWidth 属性值。但是,如果元素的布局信息没有发生变化,或者元素的布局信息发生变化,但是没有立即触发重新渲染,clientWidth 属性值可能会延迟更新。
  • 当我们修改了DOM树中一个元素的内容,比如$0.textContent = ‘fjkdljsfl’,这时候浏览器不会立刻计算它的宽度之类的,但是如果我们要立刻获取比如$0.clientWidth的时候,为了给我一个正确的结果,浏览器这时候就会花费比较多的时间重新计算布局了,我们可以验证clientWidth是一个getter函数,如果没有修改布局,直接获取,如果修改了布局,浏览器会计算完之后再返回,通过getOwnPropertyDescriptor可以看到它的属性描述符它是否是一个getter
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第20张图片
  • 第一个one每次添加之后,就要读一次offsetWidth,读的话就会耗费很多的性能,而two不需要读,所以会快很多
    简单理解clientHeight、scrollHeight、offsetHeight
      //one比two慢很多
      //添加一下就要读,读就会很久
      function one() {
        var target = document.getElementById("one");
        while (target.offsetWidth < 2000) {
          target.append("x");
        }
      }
      function two() {
        var target = document.getElementById("two");
        target.append("xxxxxxxxxx");
        var total = 2000 / (target.offsetWidth / 10);
        for (var i = 10; i < total; i++) {
          target.append("x");
        }
      }

事件处理

  • 有些程序需要处理用户的输入,浏览器通过事件处理函数,在用户点击的设定的按钮的时候,页面才会发生相应的变化
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第21张图片

事件处理器

  • 每一个时间处理器都是注册在一个上下文中的
  • 有三种写法
    第一个是写在< div οnclick=“foo()”>< /div>,这个写法属性前面要加on,并且属性的内容必须要写函数的调用,不能只写函数名,当该标签被解析构建DOM结点的时候,属性的内容会作为一个函数的函数体源代码。 实际上里面的函数是这个样子的,div就相当于this,然后通过一个with函数,实现onclick
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第22张图片
    第二种写法是node.onclick = function(){},只能赋值一个函数,所以只能为某一个时间绑定一个处理函数
    第三种是node.addEventListener(‘click’,function(e){}),这个可以多次调用,以绑定多个函数,e里面包含很多东西,例如位置,坐标等等;还有一个函数是removeEventListener(‘click’,foo),这个是删除这个事件

事件对象

  • 事件处理器里面的函数会接受一个参数,这个参数叫做事件对象
  • 事件处理函数现在在处理哪个元素的事件,它的this就是谁
  • 事件除了有click,还有keyup(这个是键盘事件),事件对象又不一样了,后面会有详细介绍

事件冒泡

  • 注册在祖先元素上的处理程序在后代元素发生相应事件时也会被调用,比如说:p标签内的一个button按钮被点击时,也会触发p元素的click事件,事件会从内向外传播。
  • 如果一个事件处理函数可以调用事件对象的stopPropagation()方法,事件就不会传播到外层标签上去了。
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第23张图片这段代码中body click会执行,但是html click就不会执行了。
  • e.stopPropagation()调用不会阻止事件在当前元素上剩余事件函数的运行,只会阻止其传入当前元素的父元素及祖先。e.stopImmediatePropagation()调用可以阻止当前元素上剩余事件函数的执行,以及阻止事件传入外层元素

补充:回流一定会触发重绘。
【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第24张图片
【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第25张图片

下面这段代码可以实现点击按钮获得按钮里面的值

DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Documenttitle>
  head>
  <body>
    <button>1button><button>2button><button>3button><button>4button
    ><button>5button><button>6button><button>7button><button>8button
    ><button>9button><button>10button><button>11button><button>12button
    ><button>13button><button>14button><button>15button><button>16button
    ><button>17button><button>18button><button>19button
    ><button>20button>
    <script>
      var buttons = document.querySelectorAll("button");
      for (var button of buttons) {
        button.addEventListener("click", function (e) {
          console.log(this.textContent);
        });
      }
    script>
  body>
html>

  • 我们也可以通过一个div,网住里面所有的button,通过绑定一个div的事件,然后通过target就可以获得div里面的元素事件了;这个也就是所谓的事件代理
    在这里插入图片描述
DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Documenttitle>
  head>
  <body>
    <div>
      <button title="foo" class="bar baz">1button>
      <button title="fod" class="bar baz">2button>
      <button title="fod" class="bar baa">3button>
      <button>4button><button>5button><button>6button><button>7button
      ><button>8button><button>9button><button>10button><button>11button
      ><button>12button><button>13button><button>14button
      ><button>15button><button>16button><button>17button
      ><button>18button><button>19button><button>20button>
    div>
    <script>
      var div = document.querySelector("div");
      div.addEventListener("click", function (e) {\
      //下面这个if我们可以替换成if(e.target.matches('button.bar[title="fod"]')
      //matches函数判断当前DOM节点是否能完全匹配对应的CSS选择器,如果匹配成功,返回true,反之则返回false
        if (
          e.target.tagName === "BUTTON" &&
          e.target.classList.contains("bar")
        ) {
          console.log(e.target.textContent);
        }
      });
    script>
  body>
html>

事件捕获

  • 事件捕获阶段就加一个参数写成true就可以了,模型是先从外到内进行捕获,然后从内到外进行冒泡
    - List item
  • 事件对象的stopPropagation()方法一定会阻止事件的传递进入下一个阶段;事件对象的stopPropagation()方法不会阻止事件在当前元素当前阶段继续执行
  • 之前的事件顺序是三个阶段,分别是事件捕获,目标阶段,事件冒泡,现在已经是两个阶段了,只有事件捕获和事件冒泡

默认行为

  • 例如a标签点击会自动打开页面,滚轮会自动滚动网页,表单里按tab会自动跳到下一项,点击表单提交将会提交表单
  • 在F12中的event Listeners我们可以看到元素具体绑定了什么事件
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第26张图片
  • 如果我们想阻止默认行为,我们可以通过preventDefault()方法,就可以阻止默认行为了,下面是使用方式,这样点击它的默认方式就消失了。
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第27张图片

被动事件和主动事件

被动事件和主动事件是与浏览器滚动行为相关的两种事件类型。被动事件的处理不会阻止浏览器的默认滚动行为,而主动事件的处理可能会阻止浏览器的默认滚动行为。

具体来说,被动事件是指那些不会调用preventDefault()方法来阻止默认滚动行为的事件。这些事件在处理时,浏览器会立即执行默认的滚动行为,而不需要等待JavaScript代码的处理。这种行为可以提高页面滚动的流畅度和响应速度,因为浏览器可以在事件处理程序之前就开始处理滚动事件。一般来说,被动事件的处理速度比主动事件更快,因为它不需要等待JavaScript代码的执行。

主动事件则是指那些可能会调用preventDefault()方法来阻止默认滚动行为的事件。这些事件在处理时,如果事件处理程序调用了preventDefault()方法,浏览器就会停止执行默认的滚动行为,从而实现自定义的滚动行为。主动事件常常用于实现一些特殊的滚动效果,比如平滑滚动和惯性滚动等。

总的来说,被动事件和主动事件的区别在于它们处理滚动事件的方式。被动事件处理时不会阻止默认滚动行为,而主动事件可能会阻止默认滚动行为。在实际开发中,需要根据具体的需求选择合适的事件类型来处理滚动事件,以实现更好的用户体验。

滚动事件

  • addEventListener前面没有点什么什么,说明是全局的,整个页面的滚动。

  • max是最大可滚动到的高度,document.body.scrollHeight是页面可滚动高度,innerHeight是窗口的可视高度

  • scrollY是滚动到窗口之外的部分有多少
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第28张图片
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第29张图片

  • 窗口上这两个
    【javascript】DOM,事件处理,事件冒泡,事件代理,事件捕获,滚动事件_第30张图片

  • 如果事件处理函数根本不会调用preventDefault(),那么还让浏览器等待事件处理函数运行完毕才执行默认行为,事件的发生和事件默认行为的执行之间就会有一延迟,延迟时间为事件处理函数的运行时间;而如果这个时间比较久,则用户就会感受到明显的延迟,但是如果我们可以让浏览器知道时间处理函数不会调用preventDefault(),则浏览器就不用等待函数的运行完才执行默认行为,那么用户就不会感受到延迟。

  • 鼠标滚动页面窗口,CSS的2D,3D相关的动画等不涉及布局计算的操作,可以跟页面内的死循环同时执行

  • 所以页面的滚动从技术上可以跟时间处理函数同时执行,但是我们要告诉浏览器,我们的事件处理函数不会阻止默认行为,浏览器不用等函数运行完才知道,通过addEventListener的第三个参数,其中对象中capture是是否捕获事件,passive是是否是被动事件(事件处理函数是在默认事件发生之后执行的,是被动事件就不会调用preventDefault()) ,once表示是否是单次事件绑定,如果是,执行一次就删掉
    在这里插入图片描述

  • 如果passive是false,那么它是主动事件,我们在函数中调用了e.preventDefault(),但浏览器不知道我们是否调用了preventDefault,我们需要运行完函数才能执行页面滚动操作,如果我们在函数里写了一个1秒钟才能执行完的函数,那么滚动就会有卡顿。

  • 如果passive是true,那么就告诉浏览器它是被动事件,不会调用e.preventDefault(),有死循环也不会卡顿。

  • 如果事件处理程序不需要调用preventDefault()方法来阻止事件的默认行为,可以将passive属性设置为true,这样可以让浏览器在事件处理程序之前立即进行滚动处理,从而提高页面滚动的流畅度和响应速度。

————————————————————————
♥♥♥码字不易,大家的支持就是我坚持下去的动力♥♥♥
版权声明:本文为CSDN博主「亚太地区百大最帅面孔第101名」的原创文章

你可能感兴趣的:(#,javascript,javascript,前端,html)