最近在实现一个功能,就是有一串列表项,每当点击其中一个项目,该项目就需要作出相对应的状态改变。如果按照传统做法,可以循环遍历该列表,添加事件监听,但有点麻烦。在某些情况下可以采用事件委托的方式。
HTML
<div class="mon-week-day" >
<div class="" >month</div>
<div class="" >week</div>
<div class="selected" >day</div>
</div>
CSS
.selected{
color:red;
}
一、
传统做法:循环遍历添加事件监听
var parent = document.getElementsByClassName("mon-week-day")[0];
var len = parent.children.length;
for(let i=0;i<len;i++){
parent.children[i].addEventListener("click",function(){
alert(this.textContent)
})
}
这里有几点需要注意:
1.element.children和element.childNodes还是有点区别的,前者不包括文本节点,后者有
2.nodeValue对于文本节点相当于文本节点的内容,但对于element、document等值为null
二、
事件委托适用于允许事件冒泡的情况,比如click、mouseover、mousout等等(像focus&blur、mouseenter&mouseleave、load&unload就没有事件冒泡)。事件冒泡容易理解,就是从内向外触发,将触发信号逐层传播到最外层。如果我们将click事件绑定在某个父元素上,实际上也能监听到子元素。
var parent = document.getElementsByClassName("mon-week-day")[0];
parent.addEventListener("click",function(e){
e.target.style.color = "red";
alert(e.target);
})
这里也有几点需要注意:
1.当事件处理程序直接添加在实际目标上,那么e.target、e.currentTarget和this是等同的,都指向实际目标。但当事件处理程序添加在父节点上(事件冒泡),e.target依旧指向实际目标,但e.currentTarget和this则指向当前事件处理程序绑定的节点。所以如果将上述代码中的e.target改为e.currentTarget,就不能达到”点击某个元素,则只是该元素发生相应变化“的目的
三、问题
问题来了,如果我只是希望点击某个元素,则只是该元素发生相应变化,且在点击同一列表的其他元素时,原先的元素可以恢复初始状态,该怎么办?
当然如果能用:hover、:focus这些伪类就可以实现那自然好,实在不行,也可以用原生JS或Jquery实现。但原生JS目前我只能是循环遍历添加监听事件,考虑到要借助事件委托的话可以用Jquery的$(e.target)实现。
比如我用class来控制样式的变化
var parent = document.getElementsByClassName("mon-week-day")[0];
for(let i of parent.children){
i.addEventListener("click",function(){
for(let i of parent.children){
i.className = "";
//console.log(i.className);
}//在正式改变class之前,要先将所有的class清空(同在一个起跑线上)
this.className = "selected";
})
}
如果用Jquery还会更简单一些
要遍历的👇
$(".mon-week-day>div").map(function(){
$(this).on("click",function(){//this引用每次迭代的DOM元素
$(this).siblings().removeClass();//把同胞元素的class值清空
$(this).attr("class","selected");
})
})
不用遍历的(事件委托)👇
$(".mon-week-day").on("click",function(e){
$(e.target).siblings().removeClass();
$(e.target).attr("class","selected");
})