案例 - 动态添加 li 元素添加事件

<button>添加</button>
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
</ul>

<script>
var oList = document.getElementsByTagName('ul')[0],
    oLi = oList.getElementsByTagName('li'),
    oBtn = document.getElementsByTagName("button")[0];
    len = oLi.length;
    
oList.onclick = function(e) {
  var e = e || window.event,
      tar = e.target || e.srcElement;

  console.log(tar.innerText);
}

oBtn.onclick = function() {
  const li = document.createElement("li");
  li.innerText = oLi.length + 1;
  oList.appendChild(li);
}
</script>
  1. 在父级绑定事件,子级触发后冒泡到父级,在通过事件源对象即可操作子级
<button>添加</button>
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
</ul>
<script>
  var oList = document.getElementsByTagName('ul')[0],
    oLi = oList.getElementsByTagName('li'),
    oBtn = document.getElementsByTagName("button")[0];
    len = oLi.length;
  
  oList.onclick = function(e) {
    var e = e || window.event,
        tar = e.target || e.srcElement;

    console.log(tar);
  }
</script>
  1. 通过 事件冒泡 获取 target
oUl.onclick = function(e){
  var e = e || window.event,
      tar = e.target || e.srcElement;
  console.log(tar);
}
  1. 点击 li 打印对应下标,绑定事件到 li 元素上
for (var i = 0; i < len; i++) {
  item = oLi[i];
  (function (i) {
    item.onclick = function () {
      console.log(i);
    };
  })(i);
}
  1. 通过事件代理获取下标
oList.onclick = function(e) {
  var e = e || window.event,
      tar = e.target || e.srcElement; // target 才是真正点击的 li 元素
  for (var i = 0; i < len; i++) {
    item = oLi[i];
    if (tar === item) {
      console.log(i);
    }
  }
}
  1. 通过 indexOf 获取,比上面方式好
oList.onclick = function(e) {
    var e = e || window.event,
        tar = e.target || e.srcElement
    var index = Array.prototype.indexOf.call(oLi, tar);
  	console.log(index);
}

🌈 手写事件委托

// 原生JS
var ul = document.querySelector('ul');
function listen(element, eventType, targetElement, fn) {
    element.addEventListener(eventType, function(e) {
        // 先拿到当前事件的直接触发对象
        var curTarget = e.target;
        // 看它是不是使用者监听的目标对象类型
        // 一旦发现不是,就执行循环
        while(!curTarget.matches(targetElement)) {
            // 先看看当前对象是不是和父元素相同
            // 相同则把当前对象置为空,且不执行回调
            if (curTarget === element) {
                curTarget = null;
                break;
            }
            // 不相同则把当前对象设置成自己的父对象
            curTarget = curTarget.parentNode;
        }
        // 是,则先看当前对象有没有值,有值则执行回调函数
        curTarget && fn(e, curTarget);
    });
};

listen(ul, 'click', 'li', function(event, el) {
    console.log(event, el);
});

// jquery
$("ul").on("click", "li", function(e) {
  console.log($(e.target).html());
});
// 这个on事件是绑定在ul上面的,li是目标元素,
// on事件内部是通过e.target来判断点击元素是不是li的