事件优化

Frontend SELF ZH
第 42 级 , 课程 3
可用

9.1 事件委托

在JavaScript中处理事件可能需要复杂的管理,以优化性能和改进应用程序的架构。

在JavaScript中优化事件处理对创建高效的web应用程序至关重要,尤其是在处理大量元素时。在这种背景下,事件委托和避免多余的处理器起着关键作用。

事件委托是一种模式,其中事件处理器设置在父元素上,而不是每个单独的子元素。这使得能够有效地管理大量子元素的事件,因为处理器只为父元素调用一次,而不是为每个元素调用。

没有事件委托的示例:

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>事件委托示例</title>
        </head>
        <body>
          <ul id="list">
            <li>元素 1</li>
            <li>元素 2</li>
            <li>元素 3</li>
          </ul>
          <script>
            const list = document.querySelector('ul');
            const items = document.querySelectorAll('#list li');

            items.forEach(item => {
              item.addEventListener('click', function(event) {
                const li = document.createElement('li');
                li.innerText = "新元素,未触发事件";
                list.appendChild(li);
                alert(`你点击了: ${event.target.textContent}`);
              });
            });
          </script>
        </body>
      </html>
    
  

问题: 如果元素列表动态增加,需要为每个新元素添加处理器。

解决方案 — 事件委托示例:

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>事件委托示例</title>
        </head>
        <body>
          <ul id="list">
            <li>元素 1</li>
            <li>元素 2</li>
            <li>元素 3</li>
          </ul>
          <script>
            const list = document.getElementById('list');
            list.addEventListener('click', function(event) {
              if (event.target.tagName === 'LI') {
                const li = document.createElement('li');
                li.innerText = "新元素,事件已触发";
                list.appendChild(li);
                alert(`你点击了: ${event.target.textContent}`);
              }
            });
          </script>
        </body>
      </html>
    
  

优点:

  • 处理器仅添加到父元素
  • 动态添加的元素将自动支持事件处理器

9.2 避免多余的处理器

为了避免性能下降,重要的是最小化事件处理器的数量,特别是如果它们附加到多个元素或频繁调用时。几个优化方法:

1. 减少处理器数量: 使用事件委托来减少处理器数量。

2. 在addEventListener中使用 once: 如果事件处理器只需执行一次,使用{ once: true }选项添加处理器。

示例:

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>一次性事件示例</title>
        </head>
        <body>
          <button id="myButton">点击我!</button>
          <script>
            const button = document.getElementById('myButton');
            button.addEventListener('click', function(event) {
              alert('你点击了按钮');
            }, { once: true });
          </script>
        </body>
      </html>
    
  

3. 防抖和节流: 这些技术对于经常被调用的事件处理器是非常有用的,比如scrollresize

9.3 防抖

防抖将多个连续的函数调用合并为一个,仅在事件流结束后执行。

示例:

JavaScript
    
      function debounce(func, wait) {
        let timeout;
        return function(...args) {
          const context = this;
          clearTimeout(timeout);
          timeout = setTimeout(() => func.apply(context, args), wait);
        };
      }

      window.addEventListener('resize', debounce(() => {
        console.log('窗口大小已调整');
      }, 300));
    
  

试着改变小部件的宽度以查看结果

防抖示例

在这个例子中,只有当用户停止输入300毫秒后,搜索函数才会被调用。

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>防抖示例</title>
        </head>
        <body>
          <div style="min-height: 55px">
            <input type="text" id="searchInput" placeholder="开始输入查询...">
            <div id="results"></div>
          </div>

          <script>
            const searchInput = document.getElementById('searchInput');
            const results = document.getElementById('results');

            function debounce(func, delay) {
              let timeout;
              return function(...args) {
                clearTimeout(timeout);
                timeout = setTimeout(() => {
                  func.apply(this, args);
                }, delay);
              };
            }

            function performSearch(event) {
              const query = event.target.value;
              results.textContent = '搜索: ' + query;
              // 模拟服务器请求
              setTimeout(() => {
                results.textContent = '你搜索了: ' + query;
              }, 500);
            }

            const debouncedSearch = debounce(performSearch, 300);

            searchInput.addEventListener('input', debouncedSearch);
          </script>
        </body>
      </html>
    
  
HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>防抖示例</title>
        </head>
        <body>
          <input type="text" id="searchInput" placeholder="开始输入查询...">
          <div id="results"></div>

          <script>
            const searchInput = document.getElementById('searchInput');
            const results = document.getElementById('results');

            function debounce(func, delay) {
              let timeout;
              return function(...args) {
                clearTimeout(timeout);
                timeout = setTimeout(() => {
                  func.apply(this, args);
                }, delay);
              };
            }

            function performSearch(event) {
              const query = event.target.value;
              results.textContent = 'Searching for: ' + query;
              // 模拟服务器请求
              setTimeout(() => {
                results.textContent = '你搜索了: ' + query;
              }, 500);
            }

            const debouncedSearch = debounce(performSearch, 300);

            searchInput.addEventListener('input', debouncedSearch);
          </script>
        </body>
      </html>
    
  

9.4 节流

戏弄 节流确保函数在指定的时间间隔内最多调用一次。

示例:

JavaScript
    
      function throttle(func, limit) {
        let inThrottle;
        return function(...args) {
          const context = this;
          if (!inThrottle) {
            func.apply(context, args);
            inThrottle = true;
            setTimeout(() => inThrottle = false, limit);
          }
        };
      }

      window.addEventListener('scroll', throttle(() => {
        console.log('窗口滚动');
      }, 300));
    
  

另一个节流示例

在这个例子中,滚动处理器不会频繁调用,最多每200毫秒调用一次,有助于防止浏览器因频繁的滚动事件而超载。

HTML
    
      <!DOCTYPE html>
      <html>
        <head>
          <title>节流示例</title>
        </head>
        <body>
          <div id="scrollContainer" style="height: 200px; overflow-y: scroll;">
            <div style="height: 1000px;"></div>
          </div>
          <div id="status">开始滚动以查看效果</div>

          <script>
            const scrollContainer = document.getElementById('scrollContainer');
            const status = document.getElementById('status');

            function throttle(func, limit) {
              let lastFunc;
              let lastRan;
              return function(...args) {
                const context = this;
                if (!lastRan) {
                  func.apply(context, args);
                  lastRan = Date.now();
                } else {
                  clearTimeout(lastFunc);
                  lastFunc = setTimeout(() => {
                    if ((Date.now() - lastRan) >= limit) {
                      func.apply(context, args);
                      lastRan = Date.now();
                    }
                  }, limit - (Date.now() - lastRan));
                }
              };
            }

            function handleScroll(event) {
              status.textContent = '滚动中... ' + new Date().toLocaleTimeString();
            }

            const throttledScroll = throttle(handleScroll, 200);

            scrollContainer.addEventListener('scroll', throttledScroll);
          </script>
        </body>
      </html>
    
  

9.5 使用被动监听器优化事件

被动事件监听器 (passive event listeners) 用于提高性能,特别是在处理滚动事件(scroll)时。当事件处理器被设置为被动时,这意味着它不会调用preventDefault(),从而允许浏览器优化性能。

示例:

JavaScript
    
      window.addEventListener('scroll', function(event) {
        console.log('滚动中');
      }, { passive: true });
    
  
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION