事件模型

一、事件模型

事件模型就是通过监听事件执行对应的监听函数。

JS添加事件有三种方法:

  1. 通过html的on属性直接添加事件监听代码,监听事件只在冒泡阶段触发

<script>
	el.setAttribute('onclick','doSomething()');
	//等同于<Element onclick = "doSomething()"> 
	// 错误写法: <Element onclick = "doSomething">
</script>
<div onclick="console.log(2)">
	<button onclick="console.log(1)">click here</button>
</div>

所以点击button时先输出1,再输出2 ,
缺点:法违反了 HTML 与 JavaScript 代码相分离的原则,将两者写在一起,不利于代码分工

  1. 节点对象事件属性,监听事件只在冒泡阶段触发

window.onload = doSomething;
div.onclick = function (event){}

优点:绑定事件可以使JavaScript代码与HTML标签分离,文档结构清晰,便于管理和开发。
缺点:同一个事件只能定义一个监听函数,如果定义两次onclick属性,后一次定义会覆盖前一次。
注意:它的值是函数名(doSomething),html on 属性的值(doSomething())

  1. 事件监听
window.addEventListener('load',doSomething,false)

语法:addEventListener(event, function, useCapture)


event:事件名
function:触发事件回调函数
useCapture:true,捕获。false,冒泡。默认false。
IE8以下不支持。

IE语法:element.attachEvent(event, function)


event:事件类型。需加“on“,例如:onclick。
function:触发事件回调函数

优点:

  • 同一个事件可以添加多个监听函数。
  • 可以解除相应的绑定 removeEventListener(event,function);
  • 能够指定在哪个阶段(捕获阶段还是冒泡阶段)触发监听函数。
  • 它是JavaScript 统一的监听函数接口,支持事件的任何对象(例如XMLHttpRequest)
封装事件监听
<input type="button" value="click me" id="btn5">
<script>
//绑定监听事件
function addEventHandler(target,type,fn){
	if(target.addEventListener){
		target.addEventListener(type,fn);
	}else{
		target.attachEvent("on"+type,fn);
	}
}

//移除监听事件
function removeEventHandler(target,type,fn){
	if(target.removeEventListener){
		target.removeEventListener(type,fn);
	}else{
		target.detachEvent("on"+type,fn);
	}
}

//测试
var btn5 = document.getElementById("btn5");
addEventHandler(btn5,"click",hello1);//添加事件hello1
addEventHandler(btn5,"click",hello2);//添加事件hello2
removeEventHandler(btn5,"click",hello1);//移除事件hello1
</script>

事件的传播分成三个阶段:

  1. 捕获阶段(capture): 从window对象传导到目标节点
  2. 目标阶段(target):在目标节点上触发
  3. 冒泡阶段(bubbling):从目标节点传导回window对象
    这三个阶段到传播模型,使得同一事件可以触发所经过节点对应的事件监听
<div>
	<p>点击</p>
</div>

如果<div><p> 两个节点都设置了click事件监听函数(捕获冒泡阶段各设置一个监听函数),对<p>点击,click事件会触发四次。


var phases = {
	1: 'capture',
	2: 'target',
	3: 'bubble'
};

var div = document.querySelector('div');
var p = document.querySelector('p');

div.addEventListener('click', callback, true);
p.addEventListener('click', callback, true);
div.addEventListener('click', callback, false);
p.addEventListener('click', callback, false);

function callback(event) {
	var tag = event.currentTarget.tagName;
	var phase = phases[event.eventPhase];
	console.log("Tag: '" + tag + "'. EventPhase: '" + phase + "'");
}
// 点击以后的结果
// Tag: 'DIV'. EventPhase: 'capture'
// Tag: 'P'. EventPhase: 'target'
// Tag: 'P'. EventPhase: 'target'
// Tag: 'DIV'. EventPhase: 'bubble'

this指向
监听函数内部的this指向触发事件的那个元素节点。

<!-- 写法一 -->
<button id="btn1" οnclick="console.log(this.id)">点击</button>
<script>
var btn = document.getElementById('btn');
// 写法二
btn.onclick = function () {
	console.log(this.id);
};
// 写法二
btn.addEventListener(
	'click',
	function (e) {
		console.log(this.id);
	},
	false
);
// 以上三种方法都是输出 btn
<script>

三、事件对象都有哪些属性,分别应用于哪些场景

事件属性指的是事件所引发的状态以及事件本身特有的一些性质。


//获取事件对象
var even = event || window.event;
//事件方法
event.preventDefaule() //阻止默认的事件行为,如链接的跳转、表单的提交;
event.stopPropagation() //阻止事件冒泡
event.target() //获取触发事件的元素
event.stopImmediatePropagation() 
//取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用(没用过)

event.type //获取事件类型
event.currentTarget //获绑定事件的元素
event.target //获触发事件元素
event.timeStamp//事件发生的时间
event.keyCode //获取键盘unicode
event.which //获取鼠标的左、中、右键(1表示左键,2表示中键,3表示右键)
event.button //获取鼠标的左、中、右键(1表示左键,2表示中键,3表示右键)
event.eventPhase 
//获取事件传播的当前阶段:1表示捕获阶段,2表示处于目标阶段,3表示冒泡阶段

//获取鼠标距离左上角x,y坐标
even.offsetX,even.offsetY //相对元素
even.clientX,even.clientY //相对浏览器
event.pageX   event.pageY//相对页面
even.screenX ,even.screenY //相对屏幕
layerX/Y //firefox用来替代offsetX/Y

四、事件委托是什么?有哪些优势,应用场景

事件委托就是利用冒泡的原理,把事件加到父元素或祖先元素上,触发执行效果。

优点:

  1. 减少DOM操作提高事件处理速度,减少事件注册,节省内存。
    添加到页面到事件越多,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,性能优化的主要思想之一就是减少DOM操作。通过事件委托,与DOM交互一次可以处理多个事件程序,大大减少DOM交互次数。
    每个函数都是一个对象,是对象就会占用内存,对象越多,内存占用率就越大,自然性能就越差了。如果要对100个li对象绑定事件,就要占用100个内存,通过事件委托,不需要去遍历元素的子节点,对一个ul对象进行操作,只需要一个内存,性能自然大大提高。
  2. 动态的添加DOM元素,不需要因为元素的改动而修改事件绑定。

五、习题

		document.querySelector('label').addEventListener('click',function () {
				console.log(1)
		})
		document.querySelector('input').addEventListener('click',function () {
				console.log(2)
		})

先打印 2,再打印 1.
事件监听默认为冒泡触发监听函数,冒泡传播方向是从子节点到父节点,所以先触发input绑定事件再触发label绑定事件

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百事可爱-后悔下凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值