Jsonz bug-log

后续更新会放在 github.com/jsonz1993/blog

0%

事件重复绑定与stopImmediatePropagation

在旧项目中,我们一般绑定事件都是用 $('selector').on('event', fn) || document.querySelector('selector').addEventListener('event', fn);

如果平时代码规范,这样写完全ojbk 点击.p 之后输出 test1

demo1
1
2
3
4
5
6
7
8
9
<div id="id">
<p class="p">test1</p>
</div>
<script>
function add(selector, fn) {
document.querySelector(selector).addEventListener('click',fn);
}
add('.p', e=> console.log(e.currentTarget.innerHTML));
</script>

但是平时如果项目不规范,代码又写的比较乱….emmmm,很有可能出现一些逻辑上的低级错误,比如这种,在某个函数调了两次,所以这里就绑定了两次…点击之后会输出两次的 test

demo2
1
2
3
4
5
6
7
8
9
10
<div id="id">
<p class="p">test1</p>
</div>
<div class="p1">test2</div>
<script>
function add(selector, fn) { document.querySelector(selector).addEventListener('click',fn); }
function fn1() { add('.p', e=> console.log(e.currentTarget.innerHTML)); };
fn1();
fn1();
</script>

这种情况平时工作不注意真的有可能发生,而且排查也只能说平时在看接口或改代码的时候 发现随手改
重复调接口情况

一般为了避免这种失误重复调用的操作,有几种方法:

  1. 把事件处理函数抽出来,这样就算重复绑定,浏览器检测到是同个函数引用,会做相应的优化,所以不会重复绑定到事件上

    1
    2
    3
    4
    5
    6
    7
    8
    <script>
    function add(selector, fn) { document.querySelector(selector).addEventListener('click',fn); }
    const evFn= e=> console.log(e.currentTarget.innerHTML);
    function fn1() { add('.p', evFn)};
    fn1();
    fn1();
    fn1();
    </script>
  2. 使用 event.stopImmediatePropagation
    官方给出的说明是:
    如果某个元素有多个相同类型事件的事件监听函数,则当该类型的事件触发时,多个事件监听函数将按照顺序依次执行.如果某个监听函数执行了 event.stopImmediatePropagation()方法,则除了该事件的冒泡行为被阻止之外(event.stopPropagation方法的作用),该元素绑定的后序相同类型事件的监听函数的执行也将被阻止.

简单来说就是,执行了event.stopImmediatePropagation() 之后,后续的绑定在该dom上的相同类型事件都不再被响应,也不冒泡。

demo3 代码,点击 test1 之后,只会在控制台输出一行 test1,其他 该元素的点击事件,#id点击事件都不会被响应

demo3
1
2
3
4
5
6
7
8
9
10
11
<div id="id">
<p class="p">test1</p>
</div>
<script>
function add(selector, fn) { document.querySelector(selector).addEventListener('click',fn); }
function fn1() { add('.p', e=> console.log(e.currentTarget.innerHTML)|| e.stopImmediatePropagation())};
add('#id',e=>console.log(1));
fn1();
fn1();
fn1();
</script>

在实际项目中,还是比较建议把事件处理逻辑抽出来当一个函数,毕竟在多人项目里面 stopImmediatePropagation 比较容易误伤队友…