javascript - 事件委托,如何准确限制事件发生在想要发生的元素上
巴扎黑
巴扎黑 2017-04-10 17:01:26
0
13
704
<ul class="buy-list">
     <li class="item">
        <p class="sour-price">
           <p class="source">京东商城</p>
           <p class="price">¥1140</p>
        </p>
        <p class="desc-buylink">
           <p class="desc">京东商城</p>
           <p class="buylink">购买</p>
        </p>
     </li>
     ...
     ...
</ul>

上面的结构,ul下面有很多li,现在我把事件委托到ul上,

代码:

var buyList = document.querySelector('.buy-list');

buyList.onclick = function(e){
     
     var target = e.target;
     
     // 只有点击li才触发事件
     
     if(target.className.indexOf('item') !== -1){
      
          // do something       
     
     }
     

}

我想实现的效果是:点击li或li内部的任意一个元素,都会执行事件。

但是上面的写法只有当我点击li时才会执行do something,点击的是sour-price 或 price元素,都不会执行do something...

请问如何实现我想要的效果?

PS:当然,判断 target.parentNodetarget.parentNode.parentNode看看是不是li也是可以的,但老觉得这么写不优雅。假设li里的结构更加复杂的话,这样写就不行了,总不能N个parentNode,一直往上找吧?

巴扎黑
巴扎黑

reply all(13)
左手右手慢动作

首先要用 addEventListener 而不用 onclick, onclick只能绑定一个事件,前者可以绑定多个。

明确的回答你用jQuery,其中有相应的用法,.on()

搞清楚了 DOM 事件处理流程,其实永原生 JS 解决问题也不难。


via:dom-event-architecture

你没说清楚点击后执行什么样的事件?子元素的事件是会冒泡到父元素的,你在父元素上添加事件处理即可。

左手右手慢动作

addEventListener用这个给li绑定事件

Peter_Zhu

jQuery中的on方法可以选择标签
on()方法

阿神

直接给li这个element绑定事件:


var listItem = document.querySelector('.item');

function doStuff(){
    ...
}
listItem.addEventListener('click', listItem, false);

li内部的任何子元素被点击,通过事件冒泡,li元素都会接受到这个点击事件。

第三个参数useCapture = false,表示handler被设置在冒泡阶段,子元素先被触发,父元素后被触发;
useCapture = true时,表示handler被设置在捕获阶段,父元素先被触发,子元素后被触发;

useCapture
If true, useCapture indicates that the user wishes to initiate capture. After initiating capture, all events of the specified type will be dispatched to the registered listener before being dispatched to any EventTargets beneath it in the DOM tree. Events which are bubbling upward through the tree will not trigger a listener designated to use capture. See DOM Level 3 Events for a detailed explanation.

另外因为这是li,所以估计你应该用querySelectorAll,在给它们绑定事件时可能会需要用到闭包,这里可以注意一下。

左手右手慢动作
function isInNodes(nodes,child){
    if(!_Type.isArray(nodes) || child.nodeType !== 1) return -1;
    var i = 0,l = nodes.length;
    while(i < l){
        if(nodes[i].nodeType === 1 && nodes[i].contains( child ) ) return i;
        i++;
    }
    return -1;
}

//判断child是否在nodes中,或子元素;返回Number||-1
这个是我用的,nodes = 所有的li,child = e.target 对象,判断点击的对象是li的哪个子元素

小葫芦

onclick只是你绑定的DOM本身的一个事件回调(方法),并不涉及事件传递,所以我觉得这也并不能称为事件委托。委托还是要用addEventListener的(仅就原生来说,jQuery里就是on)

阿神

看题主,应该是想如何有简单的方法判断element1是否是element2的descendant,答案就是自己写一个利用parentNode的函数,详见stackoverflow

大家讲道理

应该是事件冒泡问题引起的,同意zach5078的方案

阿神
var buyList = document.querySelector('.buy-list');
var findli = function(e) {
  var el = e.target;
  while(el.tagName !== 'LI') {
    el = el.parentNode;
    if (!el) {
        break;
    }
  }
  return el;
};
buyList.onclick = function(e){
     var target = e.target;
     var li = findli(e);
     if (li) {
       // 动作
     }

}
Peter_Zhu

判断target,当前触发事件的

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template