面试复盘之JS事件
JS事件模型
JavaScript事件使得网页具备互动和交互性,我们应该对其深入了解以便开发工作。在各式各样的浏览器中,JavaScript事件模型主要分为3种:原始事件模型、DOM2事件模型、IE事件模型。
原始事件模型(DOM0事件模型)
这是一种被所有浏览器都支持的模型,是最初的事件模型,对于原始事件模型来说,他是没有事件流的,事件一旦触发就立即处理,有两种实现方式
- 在HTML代码中指定属性值
<button id="demo" type="button" onclick="doSomeTing()" />
- 在JS代码中
document.getElementsById('demo').onclick = doSomeTing()
IE件模型
IE的事件模型只有两步,先执行元素的监听函数,然后事件沿着父节点一直冒泡到window。
- 实现方式
<button id="btn">+<button>
btn.attachEvent('onclick',()=>{
console.log(IE);
})
attachEvent函数接收两个参数,第一个是事件类型,第二个是事件处理函数
DOM2事件模型
此模型是W3C特制的标准模型,现代大部分浏览器都遵循这个规范。一次事件发送包含了三个阶段
- 事件捕获阶段 、 事件目标阶段 、 事件冒泡阶段 如下图
- 事件捕获:当元素触发了某个事件,window就会发出一个事件流,从window向目标元素节点流去,直到达到目标元素节点。这个过程就叫目标捕获阶段,此阶段是默认不会触发监听函数的
- 目标阶段:到达目标元素后,执行目标元素改事件对应的处理函数。
- 事件冒泡:事件流从目标元素节点向window流去的过程称为事件冒泡
- 实现方式
<button id="btn">+<button>
var btn = document.getElementById('btn')
btn.addEventListener('onclick',()=>{
console.log(DOM2);
},false)
addEventListener函数接收三个参数,第一个就是事件类型,第二个是事件处理函数,第三个是确定是否开启捕获,默认false不开启。
三种事件模型之间的区别
DOM0:
- this指向被绑定的元素
- 兼容性最强(可以兼容所有的浏览器)
- 当绑定多个同类型事件时,后面的的会覆盖前面的
- 冒泡阶段
IE模型:
- this指向window
- 兼容性差(只能在IE浏览器中运行)
- 当绑定多个同类型事件时,都从前一个一个执行
- 只有两个参数
- 目标阶段,冒泡阶段
- window.event.srcElement获取目标元素
DOM2:
- this指向被绑定的元素
- 兼容性中等(可以兼容现在的大部分浏览器)
- 当绑定多个同类型事件时,执行前者
- 三个参数
- 捕获阶段,目标阶段,冒泡阶段
- event.target 获取目标元素
event详解
事件被封装成一个event对象,包含了该事件发生时的所有的相关信息,以及可以对事件进行的操作
- event对象常见的属性、方法 如果你细看MouseEvent对象里的属性,一定会发现有很多带了X/Y的属性,这些都是和事件的位置有关的,下面详细的解释一番
- x/y与clientX/clientY值一样,表示距浏览器可视区域(工具栏除外区域)左/上的距离;
- pageX/pageY,距页面左/上的距离,它与clientX/clientY的区别是不随滚动条的位置变化;
- screenX/screenY,距计算机显示器左/上的距离,拖动你的浏览器窗口位置可以看到变化;
- ayerX/layerY与offsetX/offsetY值一样,表示距有定位属性的父元素左/上的距离。
event对象其他常用属性
- DOM事件模型中的事件对象常用属性:
- type用于获取事件类型
- target获取事件目标
- stopPropagation()阻止事件冒泡
- preventDefault()阻止事件默认行为
- IE事件模型中的事件对象常用属性:
- type用于获取事件类型
- srcElement获取事件目标
- cancelBubble阻止事件冒泡
- returnValue阻止事件默认行为
阻止冒泡、捕获、默认事件
- 阻止冒泡 DOM使用的是event.stopPropagation(),IE则是使用window.event.cancelBubble = true
function stopBubble(e){
if(e.stopPropagation){ //DOM
e.stopPropagation()
}else{ //IE
window.event.stopBubble = true
}
}
- 阻止捕获 IE没有捕获阶段,所以就不需要阻止,DOM阻止捕获的代码为 event.stopPropagation()
- 阻止默认事件 DOM使用的是 event.preventDefault(),IE使用的是window.event.returnValue = false
function stopDefault(e){
if(e.preventDefault){ //DOM
e.preventDefault()
}else{ // IE
window.event.returnValue = false
}
}
注意
-
event.stoppropagation() 阻止捕获和冒泡事件
-
event.stopImmediatePropagatipn() 还能阻止该事件目标元素节点(dom结构)注册别的同类型事件
JS事件委托
将原本挂载在自己身上的事件,委托挂载到其父级元素上。通过事件冒泡和事件捕获机制,触发子元素的事件时,事件流冒泡经过父元素时,被监听函数监听到,此时可以使用 event.target
获取到具体触发事件的元素。这就达到了父元素代替子元素做处理的要求。
<ul id="ul1">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
// DOM2
var ul2 = document.getElementById('ul1')
ul2.addEventListener('click',(e)=>{
console.log(e.target.innerText);
})
// 优化 (兼容IE和DOM0)
let ul1 = document.getElementById('ul1')
console.log(ul1);
ul1.onclick = function(e){
let event = e || window.event
let curTarget = event.target || event.srcElment
if(curTarget.tagName.toLowerCase() === 'li'){
console.log(curTarget.innerText);
}
}
- 注意,不是所有的事件都可以做事件代理的,自由支持捕获、冒泡机制的事件才可以做事件代理
- blur、focus、load和unload等事件就不能冒泡
优点
- 可以大量节约内存的占用,减少事件的注册
- 当新增内容子对象时无需对其进行事件绑定,适用于动态内容
缺点
- 可能出现事件误判,给不需要事件委托的DOM结构绑上了事件
自定义事件
我这边对其就做一些概括,不细聊。有兴趣的可以查看他的文章juejin.cn/post/684490…
什么是自定义事件
事件本身就是一种通信方式,是一种消息。在前端开发世界中,JS和HTML之间往往通过事件来进行交互。当某些基础事件无法满足我们的业务时,就可以尝试自定义事件来解决
实现方式
目前实现自定义事件的两种主要方式就是JS原生的Event()
构造函数和CustomEvent()
构造函数来创建。
演示
Event()
// 创建一个支持冒泡且不能被取消的 pingan 事件
let myEvent = new Event("pingan", {"bubbles":true, "cancelable":false});
document.dispatchEvent(myEvent);
// 事件可以在任何元素触发,不仅仅是document
testDOM.dispatchEvent(myEvent);
CustomEvent()
// 创建一个传递一个对象的pingan事件
let myEvent = new CustomEvent("pingan", {
detail: { name: "wangpingan" }
});
// 添加适当的事件监听器
window.addEventListener("pingan", e => {
alert(`pingan事件触发,是 ${e.detail.name} 触发。`);
});
document.getElementById("leo2").addEventListener(
"click", function () {
// 派发事件
window.dispatchEvent(myEvent);
}
)
Event()与CustomEvent()的区别
Event()
适合创建简单的自定义事件,而CustomEvent()
支持参数传递的自定义事件,它支持detail
参数,作为事件中需要被传递的数据,并在EventListener
获取。
JS脚本加载,页面加载
在工作过程中,经常会遇到按需加载的需求,即在脚本加载或则页码加载完成后,返回一个回调函数,在回调函数中进行相关操作,那如何去判断页面或JS脚本说否加载完成了呢?
- 下面就是一些判断的方法
如何判断页面加载完成
- window.onload = function(){} 页面加载完成后执行函数
- $(documnet).ready(functiion(){})
- document.onreadystatechange = function(){}
如何判断JS脚本加载完成
- js.onload
- js.onreadystatechnage