事件委托

70 阅读1分钟

简单版

document.getElementById("app").innerHTML = `
<ul>
    <li> <img/> </li>
    <li> <img/> </li>
    <li> <img/> </li>
    <li> <img/> </li>
    <li> <img/> </li>
</ul>`

ul.addEventListener('click', function(e){
     if(e.target.tagName.toLowerCase() === 'li'){
         fn() // 执行某个函数
     }
 })

如果点击的是<li>里面的<img/>标签, 上面的写法就无效了 ↑

改进版 ↓

document.getElementById("app").innerHTML = `
<ul id="content">
  <h1>事件委托</h1>
  <li class="item" id="1"><span>aaa</span></li>
  <li class="item" id="2"><span>bbb</span></li>
  <li class="item" id="3"><span>ccc</span></li>
</ul>
`;

const content = document.getElementById("content");
delegate(content, "li", "click", (e, target) => {
  console.log(e, target);
});
/**
 * 有可能点击了<span/> or <h1/> or <ul/>,这样就获取不到id了
 * @param {dom对象} ul 
 * @param {字符串 如: 'li'} li 
 * @param {字符串 如: 'onclick'} eventType 
 * @param {Function} callback 
 */
function delegate(ul, li, eventType, callback) {
  content.addEventListener(eventType, (e) => {
    const target = findLi(ul, li, e.target);
    target && callback.call(target, e, target);
  });
}
/**
 * @param {dom对象} ul 
 * @param {字符串 如: 'li'} li 
 * @param {dom对象} target 
 */
function findLi(ul, li, target) {
  if (target === ul) return null;// 没找到
  if (target.matches(li)) return target;// 找到了
  return findLi(ul, li, target.parentNode);
}

Edit 事件委托