DOM-事件委托、加载事件、滚动事件

514 阅读4分钟

1.事件流

事件流指的是事件完整执行过程中的流动路径 (事件触发后产生的流程)

事件流分为两个阶段

1.捕获阶段

从dom的根元素开始去执行对应的事件(从外到里)

事件捕获需要写对应代码才能看到结果

DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)

addEventListener第三个参数传入true代表是捕获阶段触发(很少使用);若传入false代表冒泡阶段触发,默认就是false(开启一个阶段另一个阶段也是存在的)

2.冒泡阶段

(从目标元素开始)当一个元素执行了这个事件,它会一级一级的往上冒泡,会依次向上调用所有父级元素的同名事件。父级元素也会执行事件)

事件捕获阶段执行方向相反(从外到内);事件监听第三个元素默认是false(冒泡阶段)

    const son = document.querySelector('.son')
    document.addEventListener('click', function () {
      alert('我是爷爷')
    }, true)
    father.addEventListener('click', function () {
      alert('我是粑粑')
    }, true)
    son.addEventListener('click', function () {
      alert('我是儿子')
    }, true)

2.事件冒泡

当一个元素的事件被触发时,同样的事件(同名事件)将会在该元素的所有祖先元素中一次被触发,这一过程被称为事件冒泡

简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的 同名事件

    const son = document.querySelector('.son')
    document.addEventListener('click',function(){
      alert('我是爷爷')
    })
    father.addEventListener('click',function(){
      alert('我是粑粑')
    })
    son.addEventListener('click',function(){
      alert('我是儿子')
    })

3.阻止冒泡

因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素。若想把事件就限制在当前元素内,就需要阻止事件冒泡。

阻止事件冒泡需要拿到事件对象

语法:事件对象.stopPropagation()

此方法可以阻断事件流动传播,不光在冒泡阶段有效,捕获阶段也有效

阻止哪个事件就在哪个事件添加

    const div = document.querySelector('div')
    const p = document.querySelector('p')
    p.addEventListener('click',function(e){
      console.log('p');
      // 阻止p冒泡到div
      // 阻止冒泡:
      // 事件对象.stopPropagation()
      e.stopPropagation()
    })
    div.addEventListener('click',function(){
      console.log('div');
    })

4.事件对象其他方法

阻止默认行为(比如a链接跳转之后的跳转)

  <script>
    // 点击a,打印内容,并且不能跳转
    const a = document.querySelector('a')
    a.addEventListener('click',function(e){
      // a点击之后,阻止默认行为
      // 事件对象.preventDefault();
      e.preventDefault()
    })
  </script>

5.两种注册事件写法

1.on事件:同类型的事件只能注册1个,无法开启捕获,只能默认冒泡

两个同类型的事件,后面的会覆盖前面的

    const btn1 = document.querySelector('.btn1')
    btn1.onclick = function(){
      alert('点击了')
      // 解绑事件
      // 元素.onclick = null
      btn1.onclick = null//只执行一次
    }
    btn1.onclick = function(){
      alert('点击第二次')//两个同类型的事件,后面的覆盖前面的
    }

2.事件监听:同类型的事件可以注册多个

元素.removeEventListener('事件类型',事件处理函数的名称) 移除某一个事件

    const btn2 = document.querySelector('.btn2')
    const f1 = function(){
      console.log('a');
    }
    const f2 = function(){
      console.log('b');
    }
    const f3 = function(){
      console.log('c');
    }
    btn2.addEventListener('click',f1)
    btn2.addEventListener('click',f2)
    btn2.addEventListener('click',f3)
      // 解绑事件
      // 匿名函数无法被解绑
    // 元素.removeEventListener('事件类型',事件处理函数的名称)  移除某一个事件
    btn2.removeEventListener('click',f1)

6.鼠标经过事件

mouseover 和 mouseout 会有冒泡效果

mouseenter 和 mouseleave 没有冒泡效果 (推荐)

7.事件委托

给父元素注册事件,当我们触发子元素的时候,会发生事件冒泡到父元素身上

事件委托流程:(把事件注册给上级元素)

1.给上级元素注册事件

2.利用事件对象.target找到目标元素

3.判断目标对象标签名是不是我要找的。用tagName:获取标签名:注意是大写的

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
  </ul>
      const ul = document.querySelector('ul')
      ul.addEventListener('click',function(e){
        // 找到目标元素(最先触发事件的元素)
        // 事件对象.target找到目标元素
        //看看是否是我们要找到的目标元素  e.target li
        //找到对象的标签名  e.target.tagName  LI
        if(e.target.tagName === 'LI'){
          e.target.style.background = 'red'
        }
      })

案例

<script>
    // 1.给父元素注册事件,当我们触发某一个子元素的时候,会发生事件冒泡到父元素身上
    // 获取父元素
    const div = document.querySelector('div')
    // 事件监听
    div.addEventListener('click',function(e){
      // 看看是否是我们要找到的目标元素
      if(e.target.tagName === 'P'){
        e.target.style.background = 'plum'
      }
    })
  </script>

8.页面加载事件

load:加载外部资源(如图片、外联CSS和JavaScript等)加载完毕时触发的事件

监听页面所有的资源加载完毕,给window添加监听事件。 当你把代码写在前面的时候,一般用window,当页面所有资源加载完毕执行

<body>
  <img src="./images/b04.jpg" alt="">
  <script>
    // 加载事件:当资源加载完毕执行的事件
    // load
    // 监听页面所有的资源加载完毕,给window添加监听事件
    // 当你吧代码写在前面的时候,一般用window,当页面所有资源加载完毕执行
    window.addEventListener('load',function(){
      console.log('所有资源');
    })
  </script>
  <script>
    // DOMContentloaded
    // 给document加
    // 无需等待样式表,图像等完全加载
    window.addEventListener('load',function(){
      console.log('window');
    })
    document.addEventListener('DOMContentload',function(){
      console.log('document');
    })
  </script>

9.页面滚动事件

事件名:scroll 滚动条在滚动的时候持续触发的事件

滚动事件、滚动条滚动的时候触发,谁有滚动条加给谁

    // 滚动条在滚动的时候持续触发的事件
    // 很多网页
    // 事件名:scroll
    // 滚动事件、滚动条滚动的时候触发,谁有滚动条加给谁
    const div = document.querySelector('div')
    div.addEventListener('scroll',function(){
      // alert('你好呀')
      // scrollTop返回的是上边卷进去的距离
      console.log(div.scrollTop);
    })
    // 点击button回到顶部
    const button = document.querySelector('button')
    button.addEventListener('click',function(){
      // 回到顶部就是卷进去的距离为0
      // div.scrollTop可以返回也可以设置
      div.scrollTop = 0
    })
  </script>

10.scroll事件

<!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>Document</title>
  <style>
    body{
      height: 3000px;
      background:linear-gradient(pink,purple);
    }
  </style>
</head>
<body>
  <script>
    // scroll:
    // 如果整个窗口具有滚动条,那么滚动事件加给窗口window
    window.addEventListener('scroll',function(){
      // 如果整个页面往上卷,那么这个事件是html的,这个scrollTop找html获取
      console.log(document.documentElement.scrollTop);
    })
  </script>
</body>
</html>

11.获取元素的位置

offsetLeft和offsetTop

获取距离为依据定位的父级元素,如果父级没有定位,那么以(文档左上角)浏览器定位

相对于定位元素的位置

12.属性选择器

<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>Document</title>
  <style>
    /* 属性选择器 */
    /* 匹配带有id属性的选择器 */
    [id]{
      background: red;
    }
    [class=c1]{
      background-color: plum;
    }
  </style>
</head>
<body>
  <div id="1">1</div>
  <div class="c1">2</div>
  <div id="c2">3</div>
  <p class="c3">6</p>
</body>
</html>