优化实战 第 07 期 - 事件处理程序的相关优化

1,118 阅读2分钟

事件流机制

向水里扔一个西瓜,

首先它会有一个下降的过程,这个过程可以理解为从最顶层元素向事件发生的具体元素(目标点)的捕获过程

之后会产生泡泡,会在最低点(具体元素)之后漂浮到水面上,这个过程相当于事件冒泡

event_stream.jpg

事件处理程序

  • 事件委托原理

    利用事件冒泡,只使用一个事件处理程序来管理一系列的类型事件

    也就是说给所有目标元素的共同祖先节点添加一个事件处理程序即可

    这样可以减少大量的内存消耗,提升性能

  • 性能解析

    页面中事件处理程序的数量与页面的整体性能直接相关

    每个函数都是对象,都占用内存空间,对象越多,性能越差

    事件处理程序所需访问的 DOM 次数会影响整个页面的就绪时间,导致页面响应缓慢

  • 事件对象

    event.target  // 触发事件的目标元素
    event.currentTarget  // 绑定事件的元素
    event.stopPropagation()  // 阻止事件冒泡
    event.preventDefault()  // 阻止元素的默认事件
    

划入划出事件

  • mouseover 和 mouseout
    <div id="box">
      <button type="button">按钮</button>
    </div>
    
    .box {
      width: 200px;
      height: 80px;
      background-color: #0f0;
    }
    
    const box = document.querySelector('#box')
    box.addEventListener('mouseover', () => {
      console.log('移动到自身和其子元素身上都会触发事件')
    })
    
  • mouseenter 和 mouseleave
    box.addEventListener('mouseenter', () => {
      console.log('只移动到自身触发事件')
    })
    

自定义事件

  • 使用场景

    事件是与 DOM 交互的最常见的方式。通过实现自定义事件,可以让事件用于非 DOM 代码中

    且触发自定义事件的 dispatchEvent同步 执行的

  • 将二进制流数据保存为本地文件

    const saveAs = (data, filename) => {
      const blob = data instanceof Blob ? data : new Blob(data)
      const node = document.createElement('a')
      Object.assign(node, {
        download: filename,
        href: URL.createObjectURL(blob),
      })
      try {
        node.dispatchEvent(new MouseEvent('click'))
      } catch(e) {
        const evt = document.createEvent('MouseEvents')
        evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null)
        node.dispatchEvent(evt)
      }
      URL.revokeObjectURL(node.href)
    }
    

滑动导航栏

  • 结构设计

    <header class="header">
      <h1 class="header-logo"><a href="/">LOGO</a></h1>
      <nav class="header-nav" id="nav">
        <a href="javascript:void(0);" id="slider"></a>
        <a href="javascript:void(0);">首页</a>
        <a href="javascript:void(0);">联系我们</a>
      </nav>
    </header>
    
  • 风格设计

    .header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 0 calc(50% - 600px);
    }
    .header-nav {
      display: inline-flex;
      position: relative;
    }
    .header-nav > a {
      position: relative;
      width: 120px; 
      height: 68px; line-height: 68px;
      text-align: center;
    }
    .header-nav > a:first-child {
      position: absolute; left: 0;
      transtion: left .25s;
    }
    

    通过给 a 标签添加 position: relative 属性来提升文本的层级,避免滑动色块覆盖

  • 利用事件委托绑定事件

    const nav = document.querySelector('#nav')
    const slideBar = document.querySelector('#slider')
    nav.addEventListener('click', event => {
      slideBar.style = `left: ${event.target.offsetLeft}px;`
    })
    
  • 一起交流学习

    加群交流看沸点