JS Web-API-事件

3. JS Web-API-事件

 

3.1 面试题

1.编写一个通用的事件监听函数
2.描述事件冒泡的流程
3.无限下拉的图片列表,如何监听每个图片的点击
 

3.2 知识点

事件绑定
事件冒泡
事件代理
 

3.3 事件绑定
// 自定义通用的绑定函数
const clickBtn = document.getElementById('button1');
clickBtn.addEventListener('click', function () {
  // e.preventDefault(); // 阻止默认行为
  console.log('bindEventFn');
})

 

3.4 事件冒泡 & 事件捕获

 
两个概念都是为了解决页面中事件流(事件发生顺序)的问题。
 

1.addEventListener
 

在了解事件冒泡和事件捕获之间,首先来了解下 addEventListener ,通过它我们可以实现事件的绑定。

 
语法:

element.addEventListener(event, function, useCapture)

 
第一个参数是需要绑定的事件(全部事件类型可查阅:https://www.runoob.com/jsref/dom-obj-event.html)

第二个参数是触发事件后要执行的函数。

第三个参数默认值是false,表示在事件冒泡的阶段调用事件处理函数,如果参数为true,则表示在事件捕获阶段调用处理函数。
 

2.事件冒泡
 

微软提出了名为事件冒泡(event bubbling)的事件流。
 

也就是说,事件会先从最内层的元素开始发生,一直向上传播,直到document对象。
( … -> body -> html -> document)

 

(受限于篇幅,在这只截取了关键代码)

// html
<div id="container1">
  <div id="container2">
    <div id="container3">
      <button id="btn">点击</button>
		</div>
	</div>
</div>
// js
<script>
  document.getElementById('container1').addEventListener('click', function (e) {
    console.log('container1', e.target);
  })
  document.getElementById('container2').addEventListener('click', function (e) {
    console.log('container2', e.target);
  })
  document.getElementById('container3').addEventListener('click', function (e) {
    console.log('container3', e.target);
  })
  document.getElementById('btn').addEventListener('click', function (e) {
    console.log('btn', e.target);
  })
</script>
// css
<style>
  #container1 {
    position: relative;
    width: 200px;
    height: 200px;
    background-color: blue;
  }
  #container2 {
    position: relative;
    width: 120px;
    height: 120px;
    background-color: yellow;
  }
  #container3 {
    position: relative;
    width: 70px;
    height: 70px;
    background-color: red;
  }
</style>

点击按钮后输出顺序:btn 、container3 、container2 、container1
 

这是因为,事件冒泡的触发会先从最内层的元素开始发生,一直向上(外层 )传播
 

3.事件捕获
 

网景提出另一种事件流名为事件捕获(event capturing)。
 

与事件冒泡相反,事件会从最外层(document)开始发生,直到(触发事件的)最具体的元素。
( document -> html -> body -> …)

 

借用事件冒泡章节的代码,只需要给 addEventListener 添加第三个参数,即表示在事件捕获阶段调用处理函数。

// ...
document.getElementById('btn').addEventListener('click', function (e) {
  console.log('btn', e.target);
}, true)
// ...

 
点击按钮后输出顺序:container1 、container2 、container3 、btn
 

这是因为,事件捕获的触发会先从最外层的元素(document )开始发生,一直向里(内层)传播。
 
 

3.5 事件代理

 
定义: 事件代理就是利用事件冒泡,只制定一个事件处理程序,就可以管理某一类型的所有事件
 

首先来看一个例子:

// 创建一个文档片段
const frag = document.createDocumentFragment();
const count = 10;
for (let i = 0; i < count; i += 1) {
  const li = document.createElement('li');
  li.innerHTML = `li - ${i} 标签`;
  frag.appendChild(li);
}
document.body.appendChild(frag);

要求:点击某个 li 标签,弹出对应的序号,弹出标签文本
 

做法一:可以为每个li标签绑定一个事件,如这样

for (let i = 0; i < count; i += 1) {
  const li = document.createElement('li');
  li.innerHTML = `li - ${i} 标签`;
  li.onclick = function () {
    alert(`li - ${i} 标签`);
  }
  frag.appendChild(li);
} 

问题来了,这里只有 10 个 li 标签,这样做是肯定没问题的,但是如果有一万个 li 标签,难道要为每个 li 标签绑定事件吗,这样子会十分消耗性能。
 

做法二:这时候可以使用事件代理,只需要在 ul 标签上绑定一次事件即可

<ul id="ulContainer"></ul>
<script>
  // 创建一个文档片段
  const frag = document.createDocumentFragment();
	const count = 10;
	for (let i = 0; i < count; i += 1) {
  	const li = document.createElement('li');
  	li.innerHTML = `li - ${i} 标签`;
  	frag.appendChild(li);
	}
	document.getElementById('ulContainer').appendChild(frag);
	document.getElementById('ulContainer').addEventListener('click', function (e) {
  	console.log(e.target);
  	alert(e.target.innerHTML);
	});
</script>

通过 e.target 就可以获取到对应的触发元素

关于 target 和 currentTarget 可以看 JavaScript 随记中关于二者区别的文章
JS target 和 currentTarget 区别
 

注意,不要滥用事件代理,比如仅有一个(极少数)标签,自然是应该绑定到对应标签即可

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值