Web APIs _day03

事件流

事件流与两个阶段说明

事件流指的是事件完整执行过程中的流动路径(事件捕获=>事件目标阶段=>事件冒泡)

简单来说:捕获阶段是从父到子    冒泡阶段是从子到父

实际工作都是使用事件冒泡为主

事件捕获 

概念:从DOM的根元素开始去执行对应的事件 (从外到里)

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

注意:

(1)addEventListener第三个参数传入 true 代表是捕获阶段触发(很少使用)

(2)若传入false代表冒泡阶段触发,默认就是false。

(3)若是用 L0 事件监听,则只有冒泡阶段,没有捕获。

(4)捕获机制必须使用事件监听的形式注册

事件冒泡

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

  • 当一个元素触发事件后,会依次向上调用所有父级元素的同名事件。(事件的类型一样)
  • 事件冒泡是默认存在的
  • L2事件监听第三个参数是 false,或者默认都是冒泡。

阻止冒泡

原因:因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素。

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

语法:事件对象.stopPropagation()

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

原因:阻止(元素)默认行为的发生,比如阻止链接的跳转,表单域跳转。

语法:e.preventDefault()

<form action="http://www.baidu.com">
    <input type="submit" value="提交">
  </form>
  <script>
    const form = document.querySelector('form')
    form.addEventListener('click', function (e) {
      //阻止表单默认提交行为
      e.preventDefault()
    })
  </script>

 解绑事件

on事件
//直接使用null覆盖偶就可以实现事件的解绑
//绑定事件
btn.onclick=function(){
alert('你好')
}
//解绑事件
btn.onclick = null
addEventListener方式

语法:removeEventListener(事件类型, 事件处理函数, [获取捕获或者冒泡阶段]) ([ ]里面的可以省略不写)

注意:匿名函数无法被解绑,必须改写成有具体名的函数。

function fn(){
alert('你好')
}

//绑定事件
btn.addEventListener('click',fn)
//解绑事件
btn.removeEventListener('click',fn)
 鼠标经过事件的区别
  • mouseover 和 mouseout 会有冒泡效果
  • mouseenter 和 mouseleave 没有冒泡效果 (推荐)
两种注册事件的区别

传统on注册(L0)

(1)同一个对象,后面注册的事件会覆盖前面注册(同一个事件)。

(2)直接使用null覆盖偶就可以实现事件的解绑

(3)都是冒泡阶段执行的

事件监听注册(L2)

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

(2)后面注册的事件不会覆盖前面注册的事件(同一个事件)

(3)可以通过第三个参数去确定是在冒泡或者捕获阶段执行

(4)必须使用removeEventListener(事件类型, 事件处理函数, 获取捕获或者冒泡阶段)

(5)匿名函数无法被解绑

事件委托

优点:减少注册次数,可以提高程序性能。

原理:事件委托其实是利用事件冒泡的特点。(给父元素注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事 件)

语法:父级元素.addEventListener('click', function(){}) 执行父级点击事件

           事件对象.target. tagName 可以获得真正触发事件的元素

tab栏切换改造 
<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>
  <script>
    //采取事件委托
    //获取父级元素
    const ul = document.querySelector('.tab-nav ul')
    const items = document.querySelectorAll('.tab-content .item')
    //添加点击事件  事件对象e
    ul.addEventListener('click', function (e) {
      //只有点击a标签才能进行添加和删除类的操作
      if (e.target.tagName === "A") {
        // 排他思想
        // 干掉别人 移除类active
        document.querySelector('.tab-nav .active').classList.remove('active')
        //当前元素添加active 当前元素是e.target
        //this指向的是ul,不能用this
        e.target.classList.add('active')
        // 下面5个大盒子    e.target.dataset.id获取的是字符串 '0'+1为'01'下面会报错
        const i = +(e.target.dataset.id)
        document.querySelector('.tab-content .active').classList.remove('active')
        //方法1
        //没有i,则需要自定义属性
        // document.querySelector(`.tab-content .item:nth-child(${i + 1})`).classList.add('active')
        //方法2
        //获取item得到的是一个数组
        items[i].classList.add('active')
      }
    })
    //以下是利用for循环完成的
    // for (let i = 0; i < as.length; i++) {
    //   // console.log(as[i])
    //   // 要给 5个链接绑定鼠标经过事件
    //   as[i].addEventListener('mouseenter', function () {
    //     // console.log('鼠标经过')
    //     // 排他思想
    //     // 干掉别人 移除类active
    //     document.querySelector('.tab-nav .active').classList.remove('active')
    //     // 我添加类 active  this 当前的那个 a
    //     this.classList.add('active')

    //     // 下面5个大盒子 一一对应  .item
    //     // 干掉别人
    //     document.querySelector('.tab-content .active').classList.remove('active')
    //     // 对应序号的那个 item 显示 添加 active 类
    //     document.querySelector(`.tab-content .item:nth-child(${i + 1})`).classList.add('active')

    //   })
    // }
  </script>

其他事件

页面加载事件

事件名:load

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

监听页面所有资源加载完毕:给 window 添加 load 事件

语法:windows.addEventListener('load',function(){})

注意:不光可以监听整个页面资源加载完毕,也可以针对某个资源绑定load事件。

事件名:DOMContentLoaded

当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像等完全加载

语法:document.addEventListener('DOMContentLoaded',function(){})

监听页面DOM加载完毕:给 document 添加 DOMContentLoaded 事件

元素滚动事件

事件名:scroll                 

监听整个页面滚动:给 window 或 document 添加 scroll 事件

语法:windows.addEventListener('scroll',function(){})

  • 监听某个元素的内部滚动直接给某个元素加即可

元素.scrollTo(x, y)

scrollTo() 方法可把内容滚动到指定的坐标

scrollLeft和scrollTop (属性)

(1)获取被卷去的大小

(2)获取元素内容往左、往上滚出去看不到的距离。

(3)这两个值是可读写的(可读可赋值)

//页面滚动事件

windows.addEventListener('scroll',function(){
//document.documentElement   HTML 文档返回对象为HTML元素
  const n = document.documentElement.scrollTop
  console.log(n)
})
页面滚动显示隐藏侧边栏 
<script>
    //获取元素
    const elevator = document.querySelector('.xtx-elevator ')
    const entry = document.querySelector('.xtx_entry ')
    //当前页面大于300px,就显示电梯
    //给页面添加滚动事件
    window.addEventListener('scroll', function () {
      const n = document.documentElement.scrollTop
      // if (n >= 300) {
      //   elevator.style.opacity = 1
      // }
      // else {
      //   elevator.style.opacity = 0
      // }

      elevator.style.opacity = n >= entry.offsetTop ? 1 : 0
      // console.log(entry.offsetTop);
    })

    //点击返回顶部
    const backTop = document.querySelector('#backTop')
    backTop.addEventListener('click', function () {
      document.documentElement.scrollTop = 0
      //window.scrollTo(0,0)  了解
    })
  </script>

页面尺寸事件

在窗口尺寸改变的时候触发事件:

windows.addEventListener(' resize ',function(){})

获取宽高

(1)获取元素的可见部分宽高(不包含边框,margin,滚动条等)

(2)clientWidth和clientHeight

元素尺寸与位置

获取宽高:

(1)offsetWidth和offsetHeight

(2)获取元素的自身宽高、包含元素自身设置的宽高、padding、border。

(3)获取出来的是数值,方便计算。

(4)注意: 获取的是可视宽高, 如果盒子是隐藏的,获取的结果是0。

获取位置:

(1)offsetLeft和offsetTop 注意是只读属性

(2)获取元素距离自己定位父级元素的左、上距离(受父级定位的影响)

offsetTop和offsetLeft 得到位置以谁为准? 

(1)带有定位的父级

(2)如果都没有则以文档左上角为准

仿新浪固定导航栏案例
<div class="content"></div>
  <div class="backtop">
    <img src="./images/close2.png" alt="">
    <a href="javascript:;"></a>
  </div>
  <script>
    // 0 获取元素
    let backtop = document.querySelector('.backtop')
    // 页面滚动事件
    window.addEventListener('scroll', function () {
      // 2. 页面检测滚动的距离
      // console.log(document.documentElement.scrollTop)
      let num = document.documentElement.scrollTop
      // 3. 进行判断显示和隐藏
      if (num >= 500) {
        //显示那个元素
        backtop.style.display = 'block'
      } else {
        // 否则隐藏元素
        backtop.style.display = 'none'

      }

    })

    // 点击链接返回顶部 backtop.children[1]
    backtop.children[1].addEventListener('click', function () {
      // 返回顶部
      // scrollTop 可读写
      document.documentElement.scrollTop = 0
    })
  </script>

总结

综合案例

复选框

<script>
    //获取大复选框
    const allCheck = document.querySelector('#checkAll')
    //获取小复选框
    const cks = document.querySelectorAll('.ck')
    //添加大复选框点击事件
    allCheck.addEventListener('click', function () {
      for (let i = 0; i < cks.length; i++) {
        cks[i].checked = this.checked
      }
    })
    //添加小复选框点击事件
    for (let i = 0; i < cks.length; i++) {
      cks[i].addEventListener('click', function () {
        allCheck.checked = document.querySelectorAll('.ck:checked').length === cks.length
      })
    }

  </script>

电梯导航

<div class="aside">
    <div class="item active">男装/女装</div>
    <div class="item">儿童服装/游乐园</div>
    <div class="item">电子产品</div>
    <div class="item">电影/美食</div>
  </div>

  <div class="content">
    <div class="neirong content1">男装/女装</div>
    <div class="neirong content2">儿童服装/游乐园</div>
    <div class="neirong content3">电子产品</div>
    <div class="neirong content4">电影/美食</div>
  </div>

  <script>

    //获取元素
    const items = document.querySelectorAll('.aside .item')
    const neirongs = document.querySelectorAll('.content .neirong')
    // 左侧aside 模块 点击谁,谁高亮
    for (let i = 0; i < items.length; i++) {
      items[i].addEventListener('click', function () {
        // 找到上一个active 移除类
        document.querySelector('.aside .active').classList.remove('active')
        // 点击谁谁添加类
        this.classList.add('active')
        // 右侧内容跟随走动  让页面滚动到对应的offsetTop值位置
        // console.log(neirongs[i].offsetTop) 找到数据值 不用给单位
        document.documentElement.scrollTop = neirongs[i].offsetTop

      })
    }
  </script>

<script>
    //第一大模块
    (function () {
      //获取元素
      const elevator = document.querySelector('.xtx-elevator ')
      const entry = document.querySelector('.xtx_entry ')
      //当前页面大于300px,就显示电梯
      //给页面添加滚动事件
      window.addEventListener('scroll', function () {
        const n = document.documentElement.scrollTop
        // if (n >= 300) {
        //   elevator.style.opacity = 1
        // }
        // else {
        //   elevator.style.opacity = 0
        // }

        elevator.style.opacity = n >= entry.offsetTop ? 1 : 0
        // console.log(entry.offsetTop);
      })
      //点击返回顶部
      const backTop = document.querySelector('#backTop')
      backTop.addEventListener('click', function () {
        document.documentElement.scrollTop = 0
        //window.scrollTo(0,0)  了解
      })
    })();

    (function () {
      //点击页面可以滑动
      const list = document.querySelector('.xtx-elevator-list')
      list.addEventListener('click', function (e) {
        if (e.target.tagName === 'A' && e.target.dataset.name) {
          //先获取这个类名
          const old = document.querySelector('.xtx-elevator-list .active')
          if (old) old.classList.remove('active')
          //当前元素添加active
          e.target.classList.add('active')
          //获得自定义属性
          //根据小盒子的属性值选择合适的大盒子
          const top = document.querySelector(`.xtx_goods_${e.target.dataset.name}`).offsetTop
          //获取对应的大盒子内容,让页面滚动到对应的位置
          document.documentElement.scrollTop = top
        }
      })

      //页面滚动,可以根据大盒子选小盒子,添加active
      window.addEventListener('scroll', function () {
        //先获取这个类名
        const old = document.querySelector('.xtx-elevator-list .active')
        if (old) old.classList.remove('active')
        //判断当前滑动的位置选择小盒子
        const news = document.querySelector('.xtx_goods_new')
        const popular = document.querySelector('.xtx_goods_popular')
        const brand = document.querySelector('.xtx_goods_brand')
        const topic = document.querySelector('.xtx_goods_topic')
        const n = document.documentElement.scrollTop
        if (n >= news.offsetTop && n < popular.offsetTop) {
          //选择第一个小盒子
          document.querySelector('[data-name=new]').classList.add('active')
        }
        else if (n >= popular.offsetTop && n < brand.offsetTop) {
          document.querySelector('[data-name=popular]').classList.add('active')
        }
        else if (n >= brand.offsetTop && n < topic.offsetTop) {
          document.querySelector('[data-name=brand]').classList.add('active')
        }
        else if (n >= topic.offsetTop) {
          document.querySelector('[data-name=topic]').classList.add('active')
        }
      })
    })();
  </script>

 

购物车加减操作

<div>
    <input type="text" id="total" value="0" readonly>
    <input type="button" value="+" id="add">
    <input type="button" value="-" id="reduce" disabled>
    <script>
      //获取元素
      const total = document.querySelector('#total')
      const add = document.querySelector('#add')
      const reduce = document.querySelector('#reduce')

      //加号操作
      add.addEventListener('click', function () {
        // console.log(typeof total.value)  string
        // i++   隐式转换
        total.value++
        reduce.disabled = false
      })
      //减号操作
      reduce.addEventListener('click', function () {
        // console.log(typeof total.value)  string
        // i--   隐式转换
        total.value--
        add.disabled = false
      })
      // 2 === '2'
    </script>
  </div>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值