7天精通Web APIs——-Dom事件进阶(理论+实战篇)(第三天)(上)

关于这一part还没写完 这一系列内容太抽象有点费时间 大家看到了可以先收藏 内容目前正在不断更新编辑中…

事件流

事件流指的是事件完整执行过程中的流动路径
分为捕获阶段和冒泡阶段
以冒泡阶段为主;也及就是没有加捕获机制的也要想着有冒泡阶段
简单来说: 捕获阶段是从大到小;冒泡阶段是从大到小
在这里插入图片描述

事件捕获

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

定义:从Dom的根元素开始去执行对应的事件 根据辈分从大到小执行
具体来说:当触发事件捕获阶段,因为是与事件有关,所以必须用到addEventListener,具体是与该方法中第三个参数有关,默认是false,所以使用时候应该为Dom.addEventListener(事件类型,事件处理函数,true)

触发顺序:
在加入了事件捕获阶段,在触发相同事件时,无论是点击子元素,还是父元素,执行的顺序一定是从父到子,也就是先alert爷爷

 <script>
        const father = document.querySelector('.father')
        const son = document.querySelector('.son')
        document.addEventListener('click', function () {
            alert('我是爷爷')
        }, true)
        father.addEventListener('click', function () {
            alert('我是爸爸')
        }, true)
        son.addEventListener('click', function () {
            alert('我是儿子')
        }, true)
    </script>

在这里插入图片描述

事件冒泡

定义:当一个元素的事件被触发时,同样的事件会从该元素以及该元素的祖先元素从小到大 的所有祖先元素中依次被触发。这一过程被称为事件冒泡。

执行的结果,如果点击儿子模块,执行的顺序分别为 我是儿子 我是爸爸 我是爷爷;点击爸爸模块,执行顺序是我是爸爸 我是爷爷;也就是符合事件冒泡的触发顺序。

    <div class="dad">
        <div class="son"></div>
    </div>
    <script>
        const dad = document.querySelector('.dad')
        const son = document.querySelector('.son')
        document.addEventListener('click', function () {
            alert('我是爷爷')
        })
        dad.addEventListener('click', function () {
            alert('我是爸爸')
        })
        son.addEventListener('click', function () {
            alert('我是儿子')
        })
    </script>

在这里插入图片描述

事件冒泡的必要性

如果没有事件冒泡,那么如果存在给大盒子添加点击事件,那么在点击小盒子的时候,就没办法触发大盒子的点击
引出:事件委托:自己不注册事件,将对应的事件注册给祖先元素,减少事件的注册,提高效率
事件的触发要么是冒泡要么是捕获
没有.true,就会出现冒泡触发

也就是我给一个大盒子添加了点击事件,因为它是事件冒泡,所以我在点击小盒子时,也会触发点击事件的函数

    <div class="father">
        <div class="son"></div>
    </div>

    <script>
        const father = document.querySelector('.father')
        const son = document.querySelector('.son')
        document.addEventListener('click', function () {
            alert('我是爷爷')
        })
        father.addEventListener('click', function () {
            alert('我是爸爸')
        })
        son.addEventListener('click', function (e) {
            alert('我是儿子')
        })
    </script>

通过mouseover和mouseleave的区别来体现事件冒泡的必要性:

mouseover+mouseout有冒泡效果 也就是即使鼠标经过的是子元素也会触发点击事件;
因为有冒泡的效果,所以在鼠标经过子元素(紫色盒子)时,通过冒泡,就会触发父元素鼠标经过事件,所以就会有鼠标经过。

<div class="dad">
        <div class="baby"></div>
    </div>
    <script>
        const dad = document.querySelector('.dad')
        dad.addEventListener('mouseover', function () {
            console.log('鼠标经过')
        })
        dad.addEventListener('mouseout', function () {
            console.log('鼠标离开')
        })
    </script>

在这里插入图片描述
mouseenter+mouseleave没有冒泡效果
所以在经过子元素和父元素时,子元素属于父元素的一部分,所以不会有鼠标经过和离开的反复横跳

<script>
        const dad = document.querySelector('.dad')
        dad.addEventListener('mouseenter', function () {
            console.log('鼠标经过')
        })
        dad.addEventListener('mouseleave', function () {
            console.log('鼠标离开')
        })
    </script>

在这里插入图片描述

阻止冒泡

步骤:

1.先要明确给哪一块区域冒泡
2.需要对这块区域阻止什么事件就注册什么事件
3.在事件处理函数中添加事件对象,并添加上 e.stopPropagation()

本质上就是就是不让这个事件触发

 son.addEventListener('click', function (e) {
            alert('我是儿子')
            e.stopPropagation()
        })

事件解绑

on事件方式 直接使用null覆盖,就可以实现事件的解绑

 <button>点击</button>
    <script>
        const btn = document.querySelector('button')
        btn.onclick = function () {
            alert('我点击了')
        }
        btn.onclick = null
    </script>

关于addEventListener事件的解绑 注意:匿名函数无法被解绑

<button>点击</button>
    <script>
        const btn = document.querySelector('button')
        function fn () {
            alert('我点击了')
        }
        btn.addEventListener('click', fn)
        btn.removeEventListener('click', fn)
    </script>

事件委托

将事件监听委托给父元素统一来处理
原理有待解释更进一步

 <ul>
        <li>1个孩子</li>
        <li>2个孩子</li>
        <li>3个孩子</li>
        <li>4个孩子</li>
        <li>5个孩子</li>
    </ul>
    <script>
        const ul = document.querySelector('ul')
        ul.addEventListener('click', function (e) {
            // console.log('哈哈哈')
            // this.style.color = 'red'
            //专门用来打印对象
            // console.dir(e.target)
            console.log(e.target.tagName)
        })
    </script>

tab栏切换

在这里插入图片描述

css设计思路主要难点是:导航栏只有给a标签添加active才会有相关选中的样式,主题内容默认设置为display:none;意思是隐藏并且不占用网页位置;也就是设置只有添加active类样式的才会显示出来。这里这个地方的active不相同,可以去不同的名字来区分。

.tab-nav ul li a.active {
border-color: #e1251b;
color: #e1251b;
}

表示给该a标签并且是含有active这个class类的添加样式

①css代码

 <style>
    * {
      margin: 0;
      padding: 0;
    }
    .tab {
      width: 590px;
      height: 340px;
      margin: 20px;
      border: 1px solid #e4e4e4;
    }
    .tab-nav {
      width: 100%;
      height: 60px;
      line-height: 60px;
      display: flex;
      justify-content: space-between;
    }
    .tab-nav h3 {
      font-size: 24px;
      font-weight: normal;
      margin-left: 20px;
    }
    .tab-nav ul {
      list-style: none;
      display: flex;
      justify-content: flex-end;
    }
    .tab-nav ul li {
      margin: 0 20px;
      font-size: 14px;
    }
    .tab-nav ul li a {
      text-decoration: none;
      border-bottom: 2px solid transparent;
      color: #333;
    }
    .tab-nav ul li a.active {
      border-color: #e1251b;
      color: #e1251b;
    }
    .tab-content {
      padding: 0 16px;
    }
    .tab-content .item {
      display: none;
    }
    .tab-content .item.active {
      display: block;
    }
  </style>

②html代码

  <div class="tab">
    <div class="tab-nav">
      <h3>每日特价</h3>
      <ul>
        <li><a class="active" href="javascript:;" data-id="0">精选</a></li>
        <li><a href="javascript:;" data-id="1">美食</a></li>
        <li><a href="javascript:;" data-id="2">百货</a></li>
        <li><a href="javascript:;" data-id="3">个护</a></li>
        <li><a href="javascript:;" data-id="4">预告</a></li>
      </ul>
    </div>
    <div class="tab-content">
      <div class="item active"><img src="./images/tab00.png" alt="" /></div>
      <div class="item"><img src="./images/tab01.png" alt="" /></div>
      <div class="item"><img src="./images/tab02.png" alt="" /></div>
      <div class="item"><img src="./images/tab03.png" alt="" /></div>
      <div class="item"><img src="./images/tab04.png" alt="" /></div>
    </div>
  </div>

js样式设置:

  • 要求:在点击对应tab栏时,导航栏和主题内容都一一对应;并且之前的选中的状态取消掉
  • 思路:获取相关元素,然后利用排他思想(所谓的排他思想就是去掉之前选中的元素,自己“上位“)

③js代码

方法一:使用for循环实现:

<script>
        const as = document.querySelectorAll('.tab-nav a')
        for (let i = 0; i < as.length; i++) {
            as[i].addEventListener('click', function (e) {
                document.querySelector('.tab-nav .active').classList.remove('active')
                e.target.classList.add('active')
                document.querySelector('.tab-content .active').classList.remove('active')
                document.querySelector(`.tab-content .item:nth-child(${i + 1})`).classList.add('active')
            })
        }
    </script>

方法二:通过事件委托的形式:

  <script>
    // 采取事件委托的形式进行tab栏切换
    // 1.获取ul父元素 因为ul只有一个
    const ul = document.querySelector('ul')
    const items = document.querySelectorAll('.tab-content .item')
    // 2.添加事件
    ul.addEventListener('click', function (e) {
      // console.log(e.target)
      // console.log(e.target.tagName)
      // 我们只有点击了a 才会进行添加类和删除类操作
      if (e.target.tagName === 'A') {
        // console.log('我选的是a')
        // 排他思想  先移除原来的active
        document.querySelector('.tab-nav .active').classList.remove('active')
        // 当前元素添加active  当前元素示e.target
        // this指向ul  不能用this
        e.target.classList.add('active')
        // console.log(e.target.dataset.id)
        const id = +e.target.dataset.id
        // 排他思想 先移除原来的active
        document.querySelector('.tab-content .active').classList.remove('active')
        // 对应的大盒子添加active
        // document.querySelector(`.tab-content .tem:nth-child($(i+1))`).classList.add('actve')
        items[id].classList.add('active')
      }
    })
  </script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值