前端中级阶段学习(1)-事件(event) 事件冒泡、捕获

11 篇文章 0 订阅
11 篇文章 0 订阅

前面我们已经基本掌握常规的语法语义,以及基本的使用方法。接下来我们讲深入进去了解其中内在的原理。

今天我们要讲什么?

  1. 事件机制
  2. 事件对象(Event)
  3. event loop

DOM (与事件的关系,看不看无所谓)

DOM(Document Object Model——文档对象模型)是用来呈现以及与任意 HTML 或 XML文档交互的 API。DOM 是载入到浏览器中的文档模型,以节点树的形式来表现文档,每个节点代表文档的构成部分(例如:页面元素、字符串或注释等等)。
DOM 是万维网上使用最为广泛的 API 之一,因为它允许运行在浏览器中的代码访问文件中的节点并与之交互。节点可以被创建,移动或修改。事件监听器可以被添加到节点上并在给定事件发生时触发
DOM 并不是天生就被规范好了的,它是浏览器开始实现JavaScript时才出现的。这个传统的 DOM 有时会被称为 DOM 0。现在, WHATWG 维护DOM现存标准。
– MDN

既然 DOM 有版本,那么在他的环境上事件的支持也是有版本的。文档

DOM 事件(0 级)

body.onclick 这种定义方式的。

  1. 不可以多次监听事件,因为是赋值的方式,下次赋值会覆盖。
  2. 只可以在冒泡阶段触发

DOM 事件(2 级)

addEventListener 方式定义的。

  1. 可以多次监听,切按监听顺序执行回调(有序)

  2. 取消监听需要同一引用的函数。举个栗子

        // 错误案例,两个方法不是同一引用,导致清除不掉
        document.addEventListener('click', function(){})
        document.removeEventListener('click', function(){})
    
        // 正确案例,同一引用,可以清除。
        function documentClick(){}
        document.addEventListener('click', documentClick)
        document.removeEventListener('click', documentClick)    
    
    
  3. 可以选择触发阶段(冒泡&捕获) capture

事件机制

标准事件:EMCAScript 标准规定事件流包含三个阶段,分别为事件捕获阶段目标阶段事件冒泡阶段
先存个代码,之后的例子我们用这个例子

<html onclick="alert('html')">
    <body onclick="alert('body')">
        <a onclick="alert('a')">click</a>
    </body>
</html>

事件捕获阶段

捕获阶段:由外到内,触发规律为 html > body > a
如果想在捕获阶段就触发,需要传入参数 {capture: true}

事件冒泡阶段

冒泡阶段:由内到外,触发规律为 a > body > html
这个阶段执行是 W3C 默认的,等价于 {capture: false}

事件执行顺序

事件的捕获阶段 > 处于目标阶段 > 事件的冒泡阶段 > 事件的默认行为
这里为什么要强调这个顺序呢?

  1. 因为默认行为是在最后面,所以我们都可以用 e.preventDefault() 来阻止。
  2. 基于上条的阻止默认事件。在移动端滑动时,阻止默认事件需要手动设置 passive 为 false
    passive: Boolean,设置为 true 时,表示 listener 永远不会调用 preventDefault()。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。
  3. 我们真正单击的元素事件触发不在冒泡和捕获阶段,而在目标阶段触发。 DEMO-冒泡&捕获阶段触发事件,可以看到,他是通过定义时的先后顺序来触发的。

事件对象(Event)

Event 对象–mdn

事件对象(属性&方法)

key类型描述
bubblesboolean是否冒泡
cancelableboolean是否可以取消的默认动作。
currentTargetElement返回其事件监听器触发该事件的元素。(this 的真实指向)
eventPhaseIntenger返回事件传播的当前阶段
targetElement返回触发此事件的元素。(事件的目标节点)
timeStampDate触发的时间戳
typeString事件名称。
isTrustedboolean该事件是否是浏览器生成(true 代表是,false 代表是开发人员创建
preventDefaultFunction取消事件的默认行为在 cancelable=true 时有效
stopPropagationFunction取消事件的捕获或者冒泡行为在 bubbles=true 时有效
  1. IE: event.cancelBubble=true; //阻止事件冒泡
  2. IE: event.returnValue=false; //阻止事件的默认行为
  3. 获取事件 window.event

事件类型(分类、Event对象之类)

DOM event 子类,根据不同的事件类型,返回的对象会有些许不同,比如 Mouse 类型的,就会有单击坐标之类的。 KeyboardEvent 之类的就会有按键之类的。

[图片上传失败…(image-a6f7e3-1561639174012)]

new 一个事件对象

CustomEvent() --mdn

document.body.onclick=function(e){console.log(e)}
var btn=document.body;
var event= new CustomEvent("click");
btn.dispatchEvent(event);

其实这里我们可以自定义事件的名称,然后我们就可以实现一个发布订阅的功能

document.addEventListener("bus", function(e) { console.log(e, e.detail) });
var event = new CustomEvent("bus", {detail: {LN_type: 'lilnong.top'}});
document.dispatchEvent(event);

event loop (事件循环)

首先,我们要牢记一件事情 js 是单线程
Event Loop 中文叫事件循环。是浏览器内部的一种机制,javaScript 单线程运行时如何不阻塞 UI
Javascript 有一个 main thread 主线程和 call-stack 调用栈(执行栈),所有的任务都会被放到调用栈(栈采用的是后进先出的规则)等待主线程执行。

任务类别&任务队列(Task Queue)

在 JavaScript 中,任务被分为两种,一种宏任务(MacroTask)也叫Task,一种叫微任务(MicroTask)

MacroTask(宏任务)

<script>setTimeoutsetIntervalsetImmediateI/OUI Rendering
异步任务会在有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。

MicroTask(微任务)

Process.nextTick(Node独有)、PromiseMutationObserver
每个宏任务执行完毕后,会检查 microTask 队列是否有回调,会按照先入先出的规则执行,都执行完再执行宏任务,如此循环。

调用栈

栈采用的是后进先出的规则,这里我们调用 a()a() 内部会调用 aa()aa() 内部又调用 aa()

function a(){return aa()}
function aa(){return aaa()}
function aaa(){return 1}
  1. a 进栈
  2. aa 进栈
  3. aaa 进栈
  4. aaa 出栈

事件循环的进程模型

  1. 选择任务队列中最先进入的任务,如果任务队列为空,则执行跳转到微任务(MicroTask)的执行步骤

  2. 任务设置为已选择任务

  3. 执行任务

  4. 任务设置为空

  5. 运行完成的任务从任务队列中删除

  6. MicroTasks 步骤:

    1. 进入 MicroTask 检查点

    2. 设置 MicroTask 检查点标志为 true

    3. 当事件循环 MicroTask 不为空时:

      1. 选择最先进入队列的任务,
      2. 设置为已选择的任务
      3. 运行
      4. 将已经执行完成的 MicroTask 改变状态
      5. 移出 MicroTask
    4. 清理IndexDB事务

    5. 设置 MicroTask 检查点的标志为false。

  7. 更新界面渲染。

  8. 返回第一步。

举个栗子(常问无聊题)

console.log('script start');

setTimeout(function() {
  console.log('setTimeout');
}, 0);

new Promise(function(reslove){
    console.log('Promise-start')
    reslove();
}).then(function() {
  console.log('Promise-end');
})
console.log('script end');

结构应该没错

  1. 任务入栈(代码块)
  2. console.log('script start'); 栈中,同步代码,直接输出
  3. function() {console.log('setTimeout');} 入 MacroTask
  4. new Promise 同步代码,执行
  5. 入栈 function(reslove){console.log('Promise-start');reslove();}
  6. 执行 console.log('Promise-start');
  7. 出栈
  8. .then(function() {console.log('Promise-end');}) 进 MicroTask
  9. console.log('script end'); 同步代码,输出
  10. 当前执行完出栈,判断 MicroTasks
  11. 执行 console.log('Promise-end');
  12. 完成所有 MicroTasks
  13. 渲染 UI
  14. MacroTasks是否有数据?
  15. 执行 MacroTasks 中第一个。
  16. console.log('setTimeout'); 输出。

[图片上传失败…(image-216f48-1561639174011)]

异步事件(消息)

  1. DOM 事件
  2. setTimeout
  3. XHR
  4. Promise

总结

  1. 事件机制

    1. 当前执行块
    2. 当前执行块的微任务队列
    3. 宏任务队列
  2. Event 事件级别

  3. addEventListener 要主要保存 function 的引用,用于解绑

  4. 队列,先进先出(想起了梗,吃多了拉)

  5. 堆栈,先进后出(想起了梗,吃多了吐)

  6. 触发阶段 捕获>目标>冒泡

  7. Event 对象,针对不同的类型,有自己独特的属性。

最后,给大家推荐一个前端学习进阶内推交流群685910553前端资料分享),不管你在地球哪个方位,
不管你参加工作几年都欢迎你的入驻!(群内会定期免费提供一些群主收藏的免费学习书籍资料以及整理好的面试题和答案文档!)

如果您对这个文章有任何异议,那么请在文章评论处写上你的评论。

如果您觉得这个文章有意思,那么请分享并转发,或者也可以关注一下表示您对我们文章的认可与鼓励。

愿大家都能在编程这条路,越走越远。

更多文章:
a
前端HTML & CSS 基础入门(1)初识

前端HTML & CSS 基础入门(2)段落及文本

前端HTML & CSS 基础入门(3)列表及其样式

前端HTML & CSS 基础入门(4)边框与背景

前端HTML & CSS 基础入门(5)超链接

前端HTML & CSS 基础入门(6)表格

前端HTML & CSS 基础入门(7)表单

前端HTML & CSS 基础入门(8)CSS盒子

前端HTML & CSS 基础入门(9)布局与定位

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值