向通过 innerHTML 添加的 HTML 元素添加事件监听器

向通过 innerHTML 添加的 HTML 元素添加事件监听器

前端开发中,经常会遇到需要动态添加 html 元素的情况,例如通过 ajax 请求获取数据后,将数据渲染到页面上。一种常见的做法是使用 innerHTML 属性将 HTML 字符串插入到指定的元素中。然而,直接使用 document.getElementById 或类似方法获取这些动态添加的元素,并为其添加事件监听器,往往会遇到问题,因为在脚本执行时,这些元素可能尚未被添加到 dom 树中。

一种有效的解决方案是使用事件委托。事件委托的核心思想是将事件监听器绑定到父元素(或更高层的祖先元素)上,而不是直接绑定到子元素上。当子元素触发事件时,事件会沿着 dom 树向上冒泡,直到被父元素捕获。在父元素的事件处理函数中,可以通过 Event.target 属性来确定实际触发事件的子元素,并根据需要执行相应的操作。

以下是一个示例,演示如何使用事件委托来处理动态添加的按钮的点击事件

<div id='movies'></div>  <script> const movies = [{     image: 'http://t1.gstatic.com/images?q=tbn:ANd9GcQsJW_I8KPZiq4mXcpRCd8uKBsUMR4Gz691k6gwEiLqVOoTl8pf',     title: 'The Life of Brian',     description: 'this is a great movie'   },   {     image: 'https://m.media-amazon.com/images/M/MV5BOTI4MDdjMmUtOTZhOS00MTYwLWEyZTUtYTdhMTQxNGM1YTUxXkEyXkFqcGdeQXVyMzg1ODEwNQ@@._V1_UX140_CR0,0,140,209_AL_.jpg',     title: 'The Wasp Woman',     description: 'this is a terrible movie'   } ];  showMovieInfo = (movies) => {   const tableDiv = document.getElementById('movies');   tableDiv.innerHTML = "";    movies.foreach(movie => {     tableDiv.innerHTML +=       `         <table class="table align-middle mb-0 bg-white">             <thead class="bg-light">                 <tr>                     <th>Movie Name</th>                     <th>Position</th>                 </tr>             </thead>             <tbody>                 <tr>                     <td>                         <div class="d-flex align-items-center">                             <img src="${movie.image}"                                 alt="" style="width: 120px; height: 120px" class="rounded-circle" />                             <div class="ms-3">                                 <p class="fw-bold mb-1">${movie.title}</p>                                 <p class="text-muted mb-0">${movie.description}</p>                             </div>                         </div>                     </td>                      <td>                         <button  type="button" data-id="showonmap" data-title="${movie.title}" class="btn btn-link btn-sm btn-rounded">                             Show on map                         </button>                     </td>                 </tr>             </tbody>         </table>`;   });    tableDiv.addEventListener('click', function(e) {     if (e.target != e.currentTarget && e.target.tagName == 'BUTTON' && e.target.hasAttribute('data-id')) {       alert(e.target.dataset.title);       // ... 在这里执行其他操作,例如“在地图上显示”     }   }) }  showMovieInfo(movies); </script>

代码解释:

  1. HTML 结构: 创建一个 div 元素,其 id 为 movies,用于存放动态生成的电影信息表格。
  2. JavaScript 代码:
    • showMovieInfo 函数:
      • 首先,获取 id 为 movies 的 div 元素。
      • 清空 div 元素的 innerHTML,以确保每次渲染都是全新的。
      • 使用 forEach 循环遍历 movies 数组,为每个电影动态生成包含电影信息的 HTML 表格,并将其追加到 div 元素的 innerHTML 中。 关键在于给 button 添加 data-id 和 data-title 属性,方便后续事件处理。
      • 事件委托: 将 click 事件监听器添加到 tableDiv 元素上。
      • 在事件处理函数中,首先判断 e.target 是否为 e.currentTarget (即 tableDiv 本身)。这是为了防止点击 tableDiv 自身触发事件。 并且确保点击的元素是 button 且拥有 data-id 属性。
      • 如果点击的元素是一个按钮,并且其 data-id 属性值为 “showonmap”,则弹出一个警告框,显示该按钮的 data-title 属性值(即电影标题)。
      • 可以在此处添加其他操作,例如“在地图上显示”电影的位置。
  3. 注意事项:
    • 确保在动态添加元素之前,父元素已经存在于 DOM 树中。
    • 在事件处理函数中,使用 event.target 属性来准确地确定触发事件的子元素。
    • 可以使用 data-* 属性将额外的信息存储在 HTML 元素中,并在事件处理函数中通过 dataset 属性来访问这些信息。

总结:

通过事件委托,我们可以有效地处理动态添加的 HTML 元素的事件响应,避免了因元素不存在而导致监听器失效的问题。 这种方法不仅可以简化代码,还可以提高性能,因为只需要将一个事件监听器绑定到父元素上,而不是为每个子元素都绑定一个事件监听器。 在处理大量动态添加的元素时,事件委托的优势尤为明显。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享