Javascript与HTML之间的交互是通过事件来实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。可以使用侦听器来预定事件,以便事件发生时执行相应的代码。
事件流
事件流 是指从页面接收事件的顺序。有意思的是,IE和网景提出不同的事件流概念。IE支持的事件流是事件冒泡,网景公司支持的事件流是事件捕获。
事件冒泡
IE的事件流叫做事件冒泡,即事件 由内向外 找监听函数。我们来看下面的代码:
<!DOCTYPE html><html lang="en"><head><title>Document</title></head><body><div id="div1">click Me</div></body></html>
如果单击了页面的
- document
传播的过程是从div到document传播,逐级向上传递。
事件捕获
网景团队的事件流叫 事件捕获 ,即事件 由外向内 找监听函数。以前面的代码为例,监听的顺序是从document向
- document
DOM事件流
“DOM2级事件”规定的事件流包括三个阶段: 事件捕获阶段,处于目标阶段、事件冒泡阶段 。首先发生的是事件捕获,为截取事件提供机会;然后是实际的目标接收到事件,最后是冒泡阶段。
接下来,我们来做个事件先捕获再冒泡的小练习吧:
html代码:
css代码<!DOCTYPE html><html><head><meta charset="utf-8"><title></title></head><body><div class="level1 x"><div class="level2 x"><div class="level3 x"><div class="level4 x"><div class="level5 x"><div class="level6 x"><div class="level7 x"></div></div></div></div></div></div></div></body></html>
Javascript代码 ```javascript const level1=document.querySelector(‘.level1’) const level2=document.querySelector(‘.level2’) const level3=document.querySelector(‘.level3’) const level4=document.querySelector(‘.level4’) const level5=document.querySelector(‘.level5’) const level6=document.querySelector(‘.level6’) const level7=document.querySelector(‘.level7’)*{box-sizing:border-box;}div[class^=level]{border:1px solid;border-radius:50%;display:inline-flex;}.level1{padding:10px;background:purple;}.level2{padding:10px;background:blue;}.level3{padding:10px;background:cyan;}.level4{padding:10px;background:green;}.level5{padding:10px;background:yellow;}.level6{padding:10px;background:orange;}.level7{width:50px;height:50px;border:1px solid;background:red;border-radius:50%;}.x{background:transparent;}
let n=1; let fn=((e)=>{ const t=e.currentTarget setTimeout(()=>{ t.classList.remove(‘x’) },n1000) n+=1 }) let fn2=((e)=>{ const t=e.currentTarget setTimeout(()=>{ t.classList.add(‘x’) },n1000) n+=1 }) level1.addEventListener(‘click’,fn,true) level1.addEventListener(‘click’,fn2) level2.addEventListener(‘click’,fn,true) level2.addEventListener(‘click’,fn2) level3.addEventListener(‘click’,fn,true) level3.addEventListener(‘click’,fn2) level4.addEventListener(‘click’,fn,true) level4.addEventListener(‘click’,fn2) level5.addEventListener(‘click’,fn,true) level5.addEventListener(‘click’,fn2) level6.addEventListener(‘click’,fn,true) level6.addEventListener(‘click’,fn2) level7.addEventListener(‘click’,fn,true) level7.addEventListener(‘click’,fn2)
最终的结果如下所示:<br /><br />可以看出,图示是先捕获再冒泡的。<a name="ZzAvo"></a>## 事件代理"事件代理"即是把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务<br />,事件代理的原理是DOM元素的事件冒泡,使用事件代理的好处是可以提高性能。<br />事件代理的使用场景如下:<br />场景一: 要给100个按钮添加点击事件,怎么办?<br />答:监听这100个按钮的祖先,等冒泡的时候判断target是不是这100个按钮中的一个。<br />代码实现:<br />HTML代码如下:```html<!DOCTYPE html><html><head><meta charset="utf-8"><title></title></head><body><div id="div1"><span>span1</span><button>click1</button><button>click2</button><button>click3</button><button>click4</button><button>click5</button><button>click6</button><button>click7</button>//一直到<button>click100</button><button>click100</button></div></body></html>
javascript代码如下:
div1.addEventListener('click',(e)=>{const t=e.targetif(t.tagName.toLowerCase()==='button'){console.log('botton被点击了')console.log('button内容是'+t.textContent)}})
使用场景二:要监听目前不存在的元素的点击事件,怎么办?
监听祖先,等点击的时候看看是不是想要监听的元素。
HTML代码如下:
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title></head><body><div id="div1"></div></body></html>
js代码如下:
setTimeout(()=>{const button=document.createElement('button')button.textContent='click 1'div1.appendChild(button)},1000)div1.addEventListener('click',(e)=>{const t=e.targetif(t.tagName.toLowerCase()==='button'){console.log('button 被click')}})
