Write By Monkeyfly
以下内容均为原创,如需转载请注明出处。
前提
- 今天在测试功能时,突然发现为
ul 中的 li元素绑定的点击事件“失效了”。即点击了没反应。
具体是这样的:
- 页面中本来就存在一个
ul列表,然后为 ul 中的 每一个 li 元素 用 on()方法 绑定了点击事件。 - 此外,页面中还有一个新增按钮,点击可以在页面中
追加 一个 ul 列表。 - 追加之后,
也为 新 ul 列表 中的 每一个 li 元素 绑定了点击事件。同样,用的也是 on() 方法。
问题来了:
-
在点击
新增 ul 列表之前,为ul 中的 li 元素绑定的点击事件还可以正常使用; -
在
新增 ul 列表之后,再次点击之前ul 中的 li 元素,你会发现:点击之后没反应。 -
通过调试代码才发现,原来是因为点击事件执行了两次,导致样式增加后又被移除。所以看起来就好像
点击事件失效了一样。 -
功能问题的动图演示如下所示:

出现问题的原因:
- 那么,为什么会出现这种问题呢?
- 刚开始我也很好奇,感觉 可能是因为自己绑定的方式有问题,所以只好自己写个
demo自行测试一下。
情景还原
- 首先,页面
HTML当中本来就存在一个静态的ul列表。【如下图所示】
<body>
<ul>
<li>我是li1</li>
<li>我是li2</li>
<li>我是li3</li>
<li>我是li4</li>
<li>我是li5</li>
</ul>
<button>增加一些li元素</button>
</body>

- 然后,在页面加载完成之后,需要为
ul中的每一个li元素添加点击事件。来实现点击选中,再次点击取消的效果。
<script>
$("ul").on("click","li",function(){
$(this).toggleClass('item');
})
</script>
- 点击 新增按钮 之后,页面中又追加了一个
新的 ul 列表。【如下图所示】
我平时遇到的比较多的情况是:在追加时就为该元素绑定了点击事件。具体如下代码所示:
//点击在 body 里 追加一个 ul 列表
$("button").on("click",function(){
$("body").append("<ul>"+
"<li onclick='change(this)'>我是li new 1</li>"+
"<li onclick='change(this)'>我是li new 2</li>"+
"<li onclick='change(this)'>我是li new 3</li>"+
"</ul>");
});
function change(obj){
$(obj).toggleClass('item');
}
- 这样做其实也没错,缺点就是太麻烦了,需要你把每个元素都加一遍点击事件。
- 如果只有一个元素还好办,绑定一次就好了。
- 但是你要是碰到
ul li 列表这样的,就需要给每一个li元素 都绑定点击事件,那就太麻烦了。 还不如直接在追加完 ul 列表之后,统一给 li 元素 绑定事件,这不就行了? 简单快捷,多方便。
于是,为简单方便,我就直接这样写了。具体如下代码所示:
//点击在 body 里 追加一个 ul 列表
$("button").on("click",function(){
$("body").append("<ul>"+
"<li>我是li new 1</li>"+
"<li>我是li new 2</li>"+
"<li>我是li new 3</li>"+
"</ul>");
//然后也需要为新增的 ul 列表中的 每一个 li 元素添加点击事件
$("ul").on("click","li",function(){
$(this).toggleClass('item');
});
});
-
- 刚开始没怎么注意,不知道这样写会存在什么样的问题。
- 等后面测试功能的时候,我才发现了问题所在:
li 元素在点击之后一点反应都没有,点了 等于 没点,样式也没变化。 - 后来打断点调试才发现:
原来是因为 li 元素 的点击事件执行了两次。
为什么会执行两次呢?
答案马上揭晓…
-
在页面加载完成之后,就为页面上
已经存在的 ul 列表中的 每一个 li 元素添加了点击事件。没错吧~

-
此时是没有任何问题的。然后,我们 点击 “新增” 按钮,页面上就会追加 一个
新的 ul 列表。

-
追加完成之后呢,又会给 新增 的
ul列表 中的 每一个li元素 添加点击事件。
注意:
-
仔细看,此时为 每一个
li元素 添加点击事件的 父元素ul,居然有两个。 -
我的本意是 只给新增的
ul列表 中的每一个li元素 添加点击事件,没想到点击按钮之后,又为 原有的ul列表 中的 每一个li元素 添加了一次点击事件。 -
这么算来,原有的
ul列表 中的 每一个li元素 就被添加了 两次 点击事件,所以每点一次就会出现执行两次的现象。

-
接下来,我们点击 原有的
ul列表中的某一个li元素 试试,看一下效果。

-
执行下一步,完成点击事件

- 继续往下执行,看看会发生什么?

-
然后你会惊奇的发现:第
3个li元素的样式消失了… -

-
现在去尝试点击一下,看一看 新旧
li元素在被点击之后有什么不同之处。

分析:
- 没错吧,新增的
li元素点击事件不受影响,而原有的li元素 就没有那么幸运了。 - 因为原有的
li元素被添加了两次点击事件,所以就会点一次执行两次,样式添加之后又被移除了。整个过程就相当于没有点击,最后看起来就好像 “点击事件失效了” 一样。
解决问题
- 那么,如何去解决呢?
- 很简单,在绑定之前先解绑就可以了。
- 原理:在第二次为
li元素添加点击事件之前,先将最开始为li元素添加的点击事件移除掉,然后重新添加一次点击事件即可。 - 这样做,既不影响最初时元素的点击功能,也不会在新增该元素之后,为新增元素添加点击事件时,又为原有的元素重复添加点击事件。
- 具体操作如下:
$("ul").off("click","li").on("click","li",function(){
$(this).toggleClass('item');
});
现在我终于明白了:为什么在绑定事件之前还需要专门解绑一次事件。以前虽然经常看到这种操作,但是不明白这么做的原因,也不知道什么情况下需要先解绑再绑定事件。
结束语
一开始我百度了一下,还以为是因为冒泡的原因。当时百度的关键词是:子元素的点击事件触发两次
搜到的结果是这样的,于是就点开看了下第一个搜索结果,看看有没有什么帮助:

- 原文中作者也遇到了和我同样的问题:点击事件执行两次,但是针对他自己的情况,他给出的结论是:不是事件绑定而是因为事件冒泡。
- 然后我以为,我的问题也是因为事件冒泡的原因。然后就试着加了
return false或者event.stopPropagation(),发现并没有效果。 - 后来经过自己打断点调试,才定位到问题所在。
- 我们都遇到了同样的问题,但我的问题确实是事件绑定的原因。而他问题的元凶则是事件冒泡。
参考资料:js(jquery)的on绑定点击事件执行两次的解决办法
至此,问题就已经完美解决了。
附录
演示 demo 的完整代码,如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>点击子元素事件执行两次</title>
<!--jquery引用自己的就行-->
<script src="jquery-3.2.1.min.js"></script>
<style>
li{
width: 100px;
height: 30px;
line-height: 30px;
background:#fff;
color:#333;
margin-top:10px;
text-align: center;
cursor:pointer;
border:1px solid #ddd;
}
li::selection{
background-color: transparent;
}
li.item{
background:#f65e62;
color:#fff;
border:none;
}
</style>
</head>
<body>
<ul>
<li>我是li1</li>
<li>我是li2</li>
<li>我是li3</li>
<li>我是li4</li>
<li>我是li5</li>
</ul>
<button>增加一些li元素</button>
<script>
$("ul").on("click","li",function(){
$(this).toggleClass('item');
})
/*$("li").on('click', function(event) {
$(this).toggleClass('item');
});*/
$("button").on("click",function(){
$("body").append("<ul><li>我是li new 1</li><li>我是li new 2</li><li>我是li new 3</li></ul>");
$("ul").off("click","li").on("click","li",function(){
$(this).toggleClass('item');
});
// $("ul").on("click","li",function(){
// $(this).toggleClass('item');
// });
});
</script>
</body>
</html>
本文详细解析了在jQuery中为元素多次绑定点击事件导致的问题及解决方法,通过正确使用off和on方法避免事件重复触发。
510

被折叠的 条评论
为什么被折叠?



