前端复盘之JS事件

722 阅读6分钟

面试复盘之JS事件

JS事件模型

JavaScript事件使得网页具备互动和交互性,我们应该对其深入了解以便开发工作。在各式各样的浏览器中,JavaScript事件模型主要分为3种:原始事件模型、DOM2事件模型、IE事件模型。

原始事件模型(DOM0事件模型)

这是一种被所有浏览器都支持的模型,是最初的事件模型,对于原始事件模型来说,他是没有事件流的,事件一旦触发就立即处理,有两种实现方式

  1. 在HTML代码中指定属性值 <button id="demo" type="button" onclick="doSomeTing()" />
  2. 在JS代码中 document.getElementsById('demo').onclick = doSomeTing()

IE件模型

IE的事件模型只有两步,先执行元素的监听函数,然后事件沿着父节点一直冒泡到window。

  • 实现方式
<button id="btn">+<button>

btn.attachEvent('onclick',()=>{
  console.log(IE);
})

attachEvent函数接收两个参数,第一个是事件类型,第二个是事件处理函数

DOM2事件模型

此模型是W3C特制的标准模型,现代大部分浏览器都遵循这个规范。一次事件发送包含了三个阶段

  • 事件捕获阶段 、 事件目标阶段 、 事件冒泡阶段 如下图 屏幕截图 2021-09-09 194951.png
  • 事件捕获:当元素触发了某个事件,window就会发出一个事件流,从window向目标元素节点流去,直到达到目标元素节点。这个过程就叫目标捕获阶段,此阶段是默认不会触发监听函数的
  • 目标阶段:到达目标元素后,执行目标元素改事件对应的处理函数。
  • 事件冒泡:事件流从目标元素节点向window流去的过程称为事件冒泡
  • 实现方式
<button id="btn">+<button>

var btn = document.getElementById('btn')
btn.addEventListener('onclick',()=>{
  console.log(DOM2);
},false)

addEventListener函数接收三个参数,第一个就是事件类型,第二个是事件处理函数,第三个是确定是否开启捕获,默认false不开启。

三种事件模型之间的区别

DOM0:

  1. this指向被绑定的元素
  2. 兼容性最强(可以兼容所有的浏览器)
  3. 当绑定多个同类型事件时,后面的的会覆盖前面的
  4. 冒泡阶段

IE模型:

  1. this指向window
  2. 兼容性差(只能在IE浏览器中运行)
  3. 当绑定多个同类型事件时,都从前一个一个执行
  4. 只有两个参数
  5. 目标阶段,冒泡阶段
  6. window.event.srcElement获取目标元素

DOM2:

  1. this指向被绑定的元素
  2. 兼容性中等(可以兼容现在的大部分浏览器)
  3. 当绑定多个同类型事件时,执行前者
  4. 三个参数
  5. 捕获阶段,目标阶段,冒泡阶段
  6. event.target 获取目标元素

event详解

事件被封装成一个event对象,包含了该事件发生时的所有的相关信息,以及可以对事件进行的操作

  • event对象常见的属性、方法 如果你细看MouseEvent对象里的属性,一定会发现有很多带了X/Y的属性,这些都是和事件的位置有关的,下面详细的解释一番
  1. x/y与clientX/clientY值一样,表示距浏览器可视区域(工具栏除外区域)左/上的距离;
  2. pageX/pageY,距页面左/上的距离,它与clientX/clientY的区别是不随滚动条的位置变化;
  3. screenX/screenY,距计算机显示器左/上的距离,拖动你的浏览器窗口位置可以看到变化;
  4. ayerX/layerY与offsetX/offsetY值一样,表示距有定位属性的父元素左/上的距离。

event对象其他常用属性

  • DOM事件模型中的事件对象常用属性:
  1. type用于获取事件类型
  2. target获取事件目标
  3. stopPropagation()阻止事件冒泡
  4. preventDefault()阻止事件默认行为
  • IE事件模型中的事件对象常用属性:
  1. type用于获取事件类型
  2. srcElement获取事件目标
  3. cancelBubble阻止事件冒泡
  4. 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
  }
}

注意

  1. event.stoppropagation() 阻止捕获和冒泡事件

  2. 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等事件就不能冒泡

优点

  1. 可以大量节约内存的占用,减少事件的注册
  2. 当新增内容子对象时无需对其进行事件绑定,适用于动态内容

缺点

  1. 可能出现事件误判,给不需要事件委托的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()的区别

  1. Event()适合创建简单的自定义事件,而CustomEvent()支持参数传递的自定义事件,它支持detail参数,作为事件中需要被传递的数据,并在EventListener 获取。

JS脚本加载,页面加载

在工作过程中,经常会遇到按需加载的需求,即在脚本加载或则页码加载完成后,返回一个回调函数,在回调函数中进行相关操作,那如何去判断页面或JS脚本说否加载完成了呢?

  • 下面就是一些判断的方法

如何判断页面加载完成

  • window.onload = function(){} 页面加载完成后执行函数
  • $(documnet).ready(functiion(){})
  • document.onreadystatechange = function(){}

如何判断JS脚本加载完成

  • js.onload
  • js.onreadystatechnage