uploadhub的技术博客 uploadhub的技术博客
首页
  • 学习笔记

    • 《HTML5和CSS3篇》
    • 《JavaScript基础篇》
    • 《JavaScript高级篇》
    • 《Ajax篇》
    • 《JavaScript模块化篇》
    • 《Node.js篇》
    • 《MongoDB篇》
    • 《Promise篇》
    • 《Git篇》
  • 《Vue2+Vue3篇》
  • 《React篇》
  • 一面-基础
  • 二三面-进阶
关于我
  • 分类
  • 标签
  • 归档

uploadhub

首页
  • 学习笔记

    • 《HTML5和CSS3篇》
    • 《JavaScript基础篇》
    • 《JavaScript高级篇》
    • 《Ajax篇》
    • 《JavaScript模块化篇》
    • 《Node.js篇》
    • 《MongoDB篇》
    • 《Promise篇》
    • 《Git篇》
  • 《Vue2+Vue3篇》
  • 《React篇》
  • 一面-基础
  • 二三面-进阶
关于我
  • 分类
  • 标签
  • 归档
  • JS基础知识(一)-变量类型和计算
  • JS基础知识(二)- 原型和原型链
  • JS基础知识(三)- 作用域、闭包
  • JS基础知识(四)- 异步和单线程
  • JS基础知识(五)- 异步进阶
  • JS-Web-API(一)- DOM & BOM
  • JS-Web-API(二)- 事件
    • 1.几道面试题(以点带面)
    • 2.涉及知识点
      • 2.1 事件绑定
      • JavaScript绑定事件的三种方式
      • 通用的事件监听函数-初版
      • 2.2 事件冒泡
      • 2.3 事件代理
      • 优化通用事件监听函数
    • 3.对前文问题的解答
      • 3.1 编写一个通用的事件监听函数
      • 3.2 描述事件冒泡的流程
      • 3.3 无限下拉的图片列表,如何监听每个图片的点击?
  • JS-Web-API(三)- Ajax
  • JS-Web-API(四)- 存储
  • HTTP协议及缓存机制
  • 开发环境
  • 运行环境
  • 一面-基础
uploadhub
2022-05-28
目录

JS-Web-API(二)- 事件

# 1.几道面试题(以点带面)

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

# 2.涉及知识点

  1. 事件绑定
  2. 事件冒泡
  3. 事件代理(又称事件委托)

# 2.1 事件绑定

# JavaScript绑定事件的三种方式

  1. 使用内联
  2. 使用.onclick的方式
  3. 使用事件监听addEventListener的方式

示例demo

<!-- 内联方式。就是在一个元素上面直接绑定了一个点击onclick事件,此事件为DOM 0级标准 -->
<!-- 同时,这个事件的优先级是最高的 -->
<input type="button" value="按钮" onclick="alert(1);">
    

<!--.onclick形式。也可以给一个DOM元素添加上一个事件。这个也是DOM 0级标准-->
<input type="button" value="按钮">
<script type="text/javascript">
	var bt = document.getElementsBytagname("input")[0];
	bt.onclick = function(){
		alert(2)
	}
</script>

<!--上述两种方式都有个弊端:一个元素只能添加一个事件-->
<!--下面这种方式addEventListener可以给一个DOM对象绑定一个或者是多个事件,推荐使用-->
<!--1.事件类型,不需要添加上on。2.事件函数。3.是否捕获(布尔值),默认是false,即不捕获,那就是冒泡-->
<input type="button" value="按钮">

<script type="text/javascript">
	var bt = document.getElementsBytagname("input")[0];
	bt.addEventListener("click", function(){
		alert(1)
	})
	bt.addEventListener("click", function(){
		alert(2)
	})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 通用的事件监听函数-初版

//通用的事件绑定函数
function bindEvent(elem,type,fn){
	elem.addEventListener(type,fn)
}

//使用示例
const btn1= document.getElementById('btn1')
bindEvent(btn1,'click',event=>{
	console.log(event.target)//获取触发的元素,注意event.target等下事件代理会用到
	event.preventDefault()//阻止默认行为
    alert('clicked') I
})
1
2
3
4
5
6
7
8
9
10
11
12

# 2.2 事件冒泡

冒泡:当一个事件发生在一个元素上,它会首先运行在该元素上的处理程序,然后运行其父元素上的处理程序,然后一直向上到其他祖先上的处理程序。

<!--示例demo-->
<body>
    <div id="div1">
        <p id="p1">激活</p>
        <p id="p2">取消</p>
        <p id="p3">取消</p>
        <p id="p4">取消</p>
    </div>
    <div id="div2">
        <p id="p5">取消</p>
        <p id="p6">取消</p>
    </div>
</body>

const p1 = document.getElementById('p1')
const body = document.body
bindEvent(p1,'click',e=>{
	e.stopPropagation()//注释掉这一行,来体会事件冒泡
	alert('激活')
})
bindEvent(body,'click',e=>{
	alert('取消')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 2.3 事件代理

事件代理,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素。事件委托,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,而不是目标元素。当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。

代理的好处:

  1. 代码简洁
  2. 减少浏览器内存占用
  3. 但是,不要滥用

有了事件代理,我们要对通用的事件监听函数做进一步优化

# 优化通用事件监听函数

<!--elem:要操作的DOM元素;type:事件;selector:要被代理的元素,elem是它的外层元素;fn:回调函数-->
function bindEvent(elem, type, selector, fn) {
    //说明只传了三个参数,没有元素需要做代理,直接操作某个DOM元素绑定事件即可
	if (fn == null) {
		fn=selector
		selector=null
	}

    //注意elem既可能是要直接加事件监听的DOM元素,也可能是帮助事件代理的外层元素
    elem.addEventListener(type,event=>{
        //拿到触发事件的元素
		const target = event.target
		if (selector) {
			//selector不为null,其需要代理绑定
            //matches方法判断DOM元素是否符合CSS选择器
            //此时如果匹配上了触发事件的是被代理元素selector,直接由其执行调用方传入的回调
            //因为要考虑selector还有兄弟元素,它们也可能触发冒泡的清空,所以要匹配筛选一下
			if (target.matches(selector)){
				fn.call(target,event)
			} 
        }else {
			//不需要代理,普通绑定
            //要操作的DOM元素直接执行调用方传入的回调
            //调用方传入的回调可能用到this,故必须用call把this指向当前触发事件的元素
			fn.call(target, event)
		}
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//使用示例
<div id="div3">
	<a href="#">a1</a><br>
    <a href="#">a2</a><br>
    <a href="#">a3</a><br>
    <a href="#">a4</a><br>
    <button>加载更多...</button>
</div>


<script>
	//普通绑定
	const btn1 = document.getElementById('btn1')
    //注意传入的回调不能用箭头函数形式,否则this不对
	bindEvent(btn1,'click', function (event){
		// console.log(event.target)//获取触发的元素
		event.preventDefault()//阻止默认行为
		alert(this.innerHTML)
	})

    //代理绑定
    const div3 = document.getElementById('div3')
    bindEvent(div3,'click','a',function (event){
        event.preventDefault()
        alert(this.innerHTML)
    }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 3.对前文问题的解答

# 3.1 编写一个通用的事件监听函数

<!--elem:要操作的DOM元素;type:事件;selector:要被代理的元素,elem是它的外层元素;fn:回调函数-->
function bindEvent(elem, type, selector, fn) {
    //说明只传了三个参数,没有元素需要做代理,直接操作某个DOM元素绑定事件即可
	if (fn == null) {
		fn=selector
		selector=null
	}

    //注意elem既可能是要直接加事件监听的DOM元素,也可能是帮助事件代理的外层元素
    elem.addEventListener(type,event=>{
        //拿到触发事件的元素
		const target = event.target
		if (selector) {
			//selector不为null,其需要代理绑定
            //matches方法判断DOM元素是否符合CSS选择器
            //此时如果匹配上了触发事件的是被代理元素selector,直接由其执行调用方传入的回调
            //因为要考虑selector还有兄弟元素,它们也可能触发冒泡的清空,所以要匹配筛选一下
			if (target.matches(selector)){
				fn.call(target,event)
			} 
        }else {
			//不需要代理,普通绑定
            //要操作的DOM元素直接执行调用方传入的回调
            //调用方传入的回调可能用到this,故必须用call把this指向当前触发事件的元素
			fn.call(target, event)
		}
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 3.2 描述事件冒泡的流程

  1. 基于DOM树形结构
  2. 事件会顺着触发元素向上冒泡
  3. 应用场景:代理(事件代理没有冒泡机制是用不了的)

# 3.3 无限下拉的图片列表,如何监听每个图片的点击?

  1. 利用事件代理机制
  2. 用 e.target 获取触发元素
  3. 用matches来判断是否是触发元素
#面试#JavaScript
JS-Web-API(一)- DOM & BOM
JS-Web-API(三)- Ajax

← JS-Web-API(一)- DOM & BOM JS-Web-API(三)- Ajax→

最近更新
01
HTTP协议及缓存机制
05-28
02
开发环境
05-28
03
JS基础知识(一)-变量类型和计算
05-28
更多文章>
Theme by Vdoing | Copyright © 2021-2023 uploadhub | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式