前言: 本类文章初衷只用作记录个人的学习博客,哪里有漏补哪里,不做任何其他商业用途。欢迎讨论,不喜勿喷。后面要是有遗漏的相关知识点,也会相应的补上。如果本篇文章能帮到你,我也会很愉快,共勉?
目录
- 事件绑定
- 事件冒泡与捕获
- 事件委托
- 阻止事件冒泡
- 阻止默认事件
事件绑定
要想让Javascript对用户的操作做出响应,首先要对DOM元素绑定事件处理函数。
- 在DOM元素中直接通过事件名绑定事件处理函数;
- 在js中通过直接赋值的方式绑定事件处理函数;
- addEventListener事件监听函数;
DOM元素中的事件绑定
function show() {console.log('show')}function hide() {console.log('hide')}function show() { console.log('show') } function hide() { console.log('hide') }function show() { console.log('show') } function hide() { console.log('hide') }
在html的事件中可以绑定一个或多个事件
<!-- show --><button onclick="show()">绑定一个函数</button><!-- hide show --><button onclick="hide();show()">绑定多个函数</button><!-- show --> <button onclick="show()">绑定一个函数</button> <!-- hide show --> <button onclick="hide();show()">绑定多个函数</button><!-- show --> <button onclick="show()">绑定一个函数</button> <!-- hide show --> <button onclick="hide();show()">绑定多个函数</button>
直接为对应的事件赋值绑定函数
通过直接赋值的方式绑定无法绑定多个函数,后面绑定的会覆盖前面
// hide会覆盖showdocument.querySelectorAll('button')[0].onclick = show;document.querySelectorAll('button')[0].onclick = hide;// hide会覆盖show document.querySelectorAll('button')[0].onclick = show; document.querySelectorAll('button')[0].onclick = hide;// hide会覆盖show document.querySelectorAll('button')[0].onclick = show; document.querySelectorAll('button')[0].onclick = hide;
绑定事件监听函数
// show和hide都会触发document.querySelectorAll('button')[0].addEventListener('click', show, {})document.querySelectorAll('button')[0].addEventListener('click', hide, {})// 移除事件监听document.querySelectorAll('button')[0].removeEventListener('click', show)// show和hide都会触发 document.querySelectorAll('button')[0].addEventListener('click', show, {}) document.querySelectorAll('button')[0].addEventListener('click', hide, {}) // 移除事件监听 document.querySelectorAll('button')[0].removeEventListener('click', show)// show和hide都会触发 document.querySelectorAll('button')[0].addEventListener('click', show, {}) document.querySelectorAll('button')[0].addEventListener('click', hide, {}) // 移除事件监听 document.querySelectorAll('button')[0].removeEventListener('click', show)
# EventTarget:addEventListener参数详解
事件冒泡与捕获
事件冒泡
当某元素执行某一种类型事件,那么从该元素起逐级向外层的元素检测是否存在与本身同样的事件。这一个过程,就叫做事件冒泡(从内向外)。
<div class="box box1">box1<div class="box box2">box2<div class="box box3">box3</div></div></div><div class="box box1"> box1 <div class="box box2"> box2 <div class="box box3">box3</div> </div> </div><div class="box box1"> box1 <div class="box box2"> box2 <div class="box box3">box3</div> </div> </div>
当点击box3时,事件会向上逐级冒泡,依次触发box2和box1,所以打印顺序是3 2 1
const boxList = document.querySelectorAll('.box');[...boxList].forEach((item, index) => {item.addEventListener('click', () => {console.log(`${index + 1}`) // 3 2 1}, false)})const boxList = document.querySelectorAll('.box'); [...boxList].forEach((item, index) => { item.addEventListener('click', () => { console.log(`${index + 1}`) // 3 2 1 }, false) })const boxList = document.querySelectorAll('.box'); [...boxList].forEach((item, index) => { item.addEventListener('click', () => { console.log(`${index + 1}`) // 3 2 1 }, false) })
事件冒泡的机制:浏览器会从box3的父元素身上找同类型事件(click),如果找到了则触发并再次向上传递(无论有没有找到都会继续向上传递)
,直到document为止。
事件捕获
事件捕获:当元素被触发事件时,从该元素的根节点(document)开始逐级向里寻找同类型事件,直到目标元素为止。这个过程就被称为事件捕获。
将addEventlistener
的第三个参数改为true则调整为事件捕获模式。此时会从最外层逐层向下寻找同类型事件,最终到目标元素。中途会依次触发相应的click事件,所以打印顺序是 1 2 3
[...boxList].forEach((item, index) => {item.addEventListener('click', () => {console.log(`${index + 1}`) // 1 2 3}, true)})[...boxList].forEach((item, index) => { item.addEventListener('click', () => { console.log(`${index + 1}`) // 1 2 3 }, true) })[...boxList].forEach((item, index) => { item.addEventListener('click', () => { console.log(`${index + 1}`) // 1 2 3 }, true) })
事件委托
事件委托:把一个元素响应事件的函数委托到另一个元素(通常是委托到它的父层或者更外层元素上,真正绑定事件的是外层元素),当事件响应到需要绑定的元素时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。
事件模型分为三个阶段:
- 捕获阶段:事件的触发响应从最顶层(document)到目标元素;
- 目标阶段:事件响应到触发事件的最底层元素上;
- 冒泡阶段:事件的触发响应从目标元素到最顶层(document);
假设我们的需求是每个li点击后都能打印出里面的内容:
<ul><li>javascript</li><li>vue</li><li>react</li><li>svelte</li></ul><ul> <li>javascript</li> <li>vue</li> <li>react</li> <li>svelte</li> </ul><ul> <li>javascript</li> <li>vue</li> <li>react</li> <li>svelte</li> </ul>
不使用事件委托,循环遍历所有li节点并依次绑定事件,这样可以做到,但会带来以下几个问题:
- 需要遍历所有的li节点并依次绑定事件(假如li节点特别多呢),对于内存消耗较大,效率较低。
- 如果li的节点在初始化之后,又再次动态插入了新的li节点,则又需要重新去编写相应的逻辑。
const lis = document.querySelectorAll('li');lis.forEach((item) => {item.addEventListener('click', (e) => console.log(e.target.innerText));})const lis = document.querySelectorAll('li'); lis.forEach((item) => { item.addEventListener('click', (e) => console.log(e.target.innerText)); })const lis = document.querySelectorAll('li'); lis.forEach((item) => { item.addEventListener('click', (e) => console.log(e.target.innerText)); })
使用事件委托,只需要将点击事件绑入外层元素(如ul)中,在用户点击相应的li时,借由冒泡的事件机制即可定位到指定li。
const ul = document.querySelector('ul');ul.addEventListener('click', (e) => console.log(e.target.innerText), false);const ul = document.querySelector('ul'); ul.addEventListener('click', (e) => console.log(e.target.innerText), false);const ul = document.querySelector('ul'); ul.addEventListener('click', (e) => console.log(e.target.innerText), false);
阻止事件冒泡
阻止事件冒泡/捕获
function stopBubble(e) {// 非IE浏览器if (e && e.stopPropagation) {e.stopPropagation();} else {// 兼容IEwindow.event.cancelBubble = true}}function stopBubble(e) { // 非IE浏览器 if (e && e.stopPropagation) { e.stopPropagation(); } else { // 兼容IE window.event.cancelBubble = true } }function stopBubble(e) { // 非IE浏览器 if (e && e.stopPropagation) { e.stopPropagation(); } else { // 兼容IE window.event.cancelBubble = true } }
阻止默认事件
阻止默认事件阻止就是某些元素自带的默认行为,如果元素本身没有默认行为,调用自然就无效了。拥有默认行为的元素如<a href="">
,<input type="sumbit">
等。
function preventDefault() {// 非IE浏览器if (e && e.preventDefault) {e.preventDefault();} else {// 兼容IEwindow.event.returnValue = true}}function preventDefault() { // 非IE浏览器 if (e && e.preventDefault) { e.preventDefault(); } else { // 兼容IE window.event.returnValue = true } }function preventDefault() { // 非IE浏览器 if (e && e.preventDefault) { e.preventDefault(); } else { // 兼容IE window.event.returnValue = true } }