document绑定click事件无效_DOM事件模型及不同leval的比较和事件冒泡事件委托

html中的事件写法与DOM的区别

html里写事件函数要写调用的:

<script>
function print(){
  console.log(‘hi’)
}
</script>
 
<button id=”x” onclick=”print”>A</button>
<button id=”y” onclick=”print()”>B</button>
<button id=”z” onclick=”print.call()”>C</button>

上面的代码B和C是正确的,因为在html中实际上就是给事件后面的代码加了一个eval(“要执行的代码”);

一旦用户点击,浏览器就eval(“要执行的代码”)而A就变成了 eval(“print”)就直接得到的是print这个函数,而并没有执行函数

DOM leave 0中的事件写法

X.onclick = print;  //类型为函数对象

一旦用户点击,那么浏览器就直接帮你调用这个函数

x.onclick.call(x,{})

问题:

因为事件是赋值操作所以同一个对象的相同事件函数,先写的会被后面覆盖掉:

x.onclick = function(){
  console.log(‘1’)
}
x.onclick = function(){
  console.log(‘2’)
}

上面的代码1不会被打印出来,因为被后面的2给覆盖掉了


DOM leave 2 中的事件写法

x.addEventListener(‘click’,function(){
  console.log(1)
})
x.addEventListener(‘click’,function(){
  console.log(2)
})

上面的1和2都会被打印出来,不会别覆盖掉,先写的代码先执行

function f1(){
  console.log(1)
}
function f2(){
  console.log(2);
}
function f3(){
  console.log(3);
}
x.addEventListener('click',f1)
x.addEventListener('click',f2);
x.removeEventListener('click',f1);
x.addEventListener('click',f3);
x.removeEventListener('click',f3);

上面的代码执行后只打印出2来,因为1和三紧接着被移除了

前面说的.one()事件实际上就是下面的代码:

function f1(){
 console.log(1);
 x.removeEventListener('click',f1)
}    
x.addEventListener('click',f1)

上面的代码f1只会执行一次打印出1,再次点击就不会执行,也就是one事件函数


事件捕获冒泡

<div id="grand1">
 爷爷
  <div id="parent1">
 父亲
    <div id="child1">
 儿子
    </div>
  </div>
</div>

24cd241f4810f8dbaf1101f6dec2c497.png

//1.当我点击儿子的时候,我是否点击了父亲和爷爷

//yes

//2.当我点击儿子的时候,三个函数是否调用

//yes

grand1.addEventListener('click',function(){
  console.log('爷爷');
})
parent1.addEventListener('click',function(){
  console.log('爸爸');
})
child1.addEventListener('click',function(){
  console.log('儿子');
})

//三个函数的执行顺序

//1.addEventListener里面的第三个参数是false(包括五个falsy值undefined,null,'',0,NaN)或者不传第三个参数,顺序都是:儿子爸爸爷爷(从下往上执行,又叫冒泡)

//2.当传入的第三个参数是true,顺序就是:爷爷爸爸儿子(从上往下,又叫捕获)

//上面的上就是上一级,下就是下一级

//特殊情况如果当前这个元素有两个相同事件,并且第三个参数一个是true,一个是false,那么她们的执行顺序就是先写的那个先执行:

child1.addEventListener('click',function(){
  console.log('儿子冒泡');
},false)
child1.addEventListener('click',function(){
  console.log('儿子捕获');
},true)

上面的代码先打印出“儿子冒泡”因为他先写的


Js中的阻止传播(阻止冒泡)

document.getElementById(‘div’).addEventListener(‘click’,function(e){
  e.stopPropagation();
})

jq中的阻止冒泡

只需在绑定事件后面写一个false,就相当于同时阻止传播和阻止默认事件

$(‘div’).on(‘click’,false)
//等价于
$(‘div’).on(‘click’,function(e){
  e.preventDefault();
  e.stopPropagation();
})

注意jq的false会阻止默认行为,如果页面里有单选框等会无法选中

542a068e2e2e073426cafbb24eb1e1b1.png

上面的因为wrapper里面有复选框,所以设置了false后无法选中,所以阻止默认事件一般不要在一个div上做

7887065e43adc129c8156aa1763dc27a.png

上面的代码document是在clickMe触发以后才需要隐藏的,如果把它直接用来监听太浪费内存,所以最好是写在clickMe监听事件里,而且让他每次点击后只执行一次

d2f5d887e42eadf71acc2e7e08c25432.png

当点击clickMe后触发document监听事件,并且只监听一次,点击后立刻就从内存中删除了


在冒泡的过程中去后面添加事件处理函数

a524868375853e98cd9b620f475b6e10.png

上面的代码当你点击一次,popover显示,然后给document添加了一次click事件,可是并没有再次点击触发document的click事件,只是点了一次,它却执行了document里面的东西

0d99c9d452fbac50a1b85f7efaaa3396.png

上面的图就是很好的解释,当点击一次button后,button这个函数就被调用了,也就是fn.call(),fn里面一共做两件事情,第一件就是popover显示(show),第二件就是给document添加监听事件,假设document的监听函数名是fn2,因为上面的函数中没有setTimeout等异步代码,所以fn2立刻马上会放到document的处理队列里,又因为你并没有阻止他冒泡,所以当你点击了一次button后,他执行完button自身的事件后就会继续往上找他的父级里的事件,找到document后就会直接执行fn2.call(),因此document事件里的东西才会被打印出来。


在当前冒泡阶段结束后再执行某一事件(等一会再执行)

8f7fc21d4ca373825d33c7f528fb24c9.png

上面的代码第一次点击的时候setTimeout(即使后面的参数是0也不是立刻执行,而只能说是尽快执行)里面的事件监听函数没有立刻执行,而是在冒泡结束后才会执行,也就是当click队列结束后,才在document队列里添加了一个click事件,就相当于fn3,而在下一次点击的时候这个事件才会被执行

58c8e6bd9b6566a971b12570a8087137.png

第二次点击时就会先执行button里的打印出show然后开始冒泡找到document,打印出“click事件走到了document”,又因为第一次click结束后给document又添加了一个监听事件fn3,所以这一次直接执行它,就相当于fn3.call(),所以会接着打印出“我觉得这里不会执行”、“hide”,最后冒泡结束后再回过头来执行setTimeout里的打印出“添加 one click”


事件委托

事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素;

一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。

举个例子,比如一个宿舍的同学同时快递到了,一种方法就是他们都傻傻地一个个去领取,还有一种方法就是把这件事情委托给宿舍长,让一个人出去拿好所有快递,然后再根据收件人一一分发给每个宿舍同学;

在这里,取快递就是一个事件,每个同学指的是需要响应事件的 DOM 元素,而出去统一领取快递的宿舍长就是代理的元素,所以真正绑定事件的是这个元素,按照收件人分发快递的过程就是在事件执行中,需要判断当前响应的事件应该匹配到被代理元素中的哪一个或者哪几个。

对于动态生成的标签的设置

js写法:

如果一个标签是通过动态创建的,不是一开始页面里有的,那么对这个新生成的标签通过正常的绑定事件设置是无效的,我们要对它的父标签绑定事件

如:

<ul id="ulbox">
  <li>aaa</li>
  <li>bbb</li>
  <li>ccc</li>
</ul>

上面的代码ul里面当前只有三个li,我们要给这三个li绑定一个点击事件来获取他们里面的文字内容,这种情况下完全可以直接绑定li

var ul = document.querySelector('#ulbox');
  var lis = ul.children;
  for(var i = 0;i<lis.length;i++){
    lis[i].addEventListener('click',function(event){
      console.log(event.target.innerText)
    })
  }

通过上面的代码我们可以实现点击相应的li得到里面的文字,我点击aaa所在的li,就会打印出aaa

07534d6be827c2b4e196b19c0d3171d6.png

但是我如果在现在的li的基础上在动态的添加一个li,这个li点击的时候还会得到相应的文字吗?

var li = document.createElement('li');
li.innerText = 'ddd';
ul.appendChild(li)

我通过上面的代码在现有的li上又加了一个ddd,但当我点击他的时候,并未打印出我想要的ddd

3f6af2ff020a5e0987fbdfcdcb0b8bdc.png

因为我们在一开始就获取了li的长度3,所以你不管再怎么添加,对于你代码里的li的长度总是是3,所以只对li里的前三个点击才能得到我们想要的文字,那我要得到所有的li(包括我后期动态创建上去的)里面的内容,该怎么办,因为li的长度是一直在变得,所以我们可以考虑对它的父级进行绑定事件也就是事件委托

ul.addEventListener('click',function(event){
    console.log(event.target.innerText)
})

通过上面的代码对父元素绑定事件,然后点击子元素li,得到每个li的文字内容,这里的event.target其实就是你点击的li,你可以认为,event.target永远都是它的子级元素,就等同于给li绑定事件时的event.target,这时候,就可以得到所有的li的文字了

94e9046e7422837d8d4d52d414ce393f.png

jq写法

  • $.on: 基本用法:
 $(ul).on('click','li',function(){
   console.log($(this).text())
 })

它是 ul元素之下的 li 元素的事件代理到 $(ul) 之上,只要在这个元素上有点击事件,就会自动寻找到 ul 元素下的 li元素,然后响应事件;

  • $.delegate: 基本用法:
 $(ul).delegate('li', 'click', function () { console.log('click event on tag li'); })

同上,并且还有相对应的 $.delegate 来删除代理的事件;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值