带你彻底搞懂JavaScript的事件流

目录
  • DOM事件流
    • 事件冒泡
    • 事件捕获
    • 情景一:直接在HTML中绑定事件
    • 情景二:[domNode].onclick()方式——DOM0级
    • 情景三:[domNode].addEventListener()方式——DOM2级
  • 总结

DOM事件流

要明白事件流,首先我们要明白三点:

  • 元素不是独立的,是串联在一起的
  • 单个元素触发事件以后还会影响其他元素
  • 事件流的方式:事件捕获(网景提出)、事件冒泡(IE提出)

我们就以上图为例,假设你给div绑定了点击事件,当你点击了div后,其他元素也会受之牵连,会引起牵一发而动全身的效果

事件流的方式有两种:事件冒泡事件捕获

事件冒泡

事件冒泡阶段:在点击完div后立即触发目标事件,然后再一层一层向上冒泡

事件捕获

事件捕获阶段:在点击完div后不会立即触发div的事件,而是一层一层向下捕获,最终到达div才触发事件。

其实,这两种阶段,在日后的项目开发中都有可能遇见,因为不同的绑定事件方法,造就了不同的事件阶段(冒泡/捕获)

情景一:直接在HTML中绑定事件

<body onclick="console.log('我是body')">
    <button onclick="console.log('我是button')">
        <span onclick="console.log('我是span')">快乐按钮</span>
    </button>
</body>

效果:

从上图可看出,当我们点击span标签以后,上层button身上的事件以及body身上的事件都会按冒泡顺序执行

情景二:[domNode].onclick()方式 —— DOM0级

html:

<body>
    <button>
        <span>快乐按钮</span>
    </button>
</body>

javascript:

var body = document.getElementsByTagName('body')[0];
var button = document.getElementsByTagName('button')[0];
var span = document.getElementsByTagName('span')[0];
body.onclick = function() {console.log('我是body')};
button.onclick = function() {console.log('我是button')};
span.onclick = function() {console.log('我是span')};

效果:

我们发现,DOM0级绑定事件的方式依然是冒泡的形式

情景三:[domNode].addEventListener()方式 —— DOM2级

addEvenListener(事件名,事件触发后的回调,布尔值)

false(默认):表示在冒泡阶段调用事件处理程序true:表示在捕获阶段调用事件处理程序

html:

<body>
    <button>
        <span>快乐按钮</span>
    </button>
</body>

javascript:

var body = document.getElementsByTagName('body')[0];
var button = document.getElementsByTagName('button')[0];
var span = document.getElementsByTagName('span')[0];
function theName() {console.log('我是' + this.nodeName)};
body.addEventListener('click',theName,false);
button.addEventListener('click',theName,false);
span.addEventListener('click',theName,false);

效果:

我们可以看到当addEventListener的第三个参数为false(不写默认也是false)的时候,事件流为冒泡。

当我们把第三个参数改为true时:

......
body.addEventListener('click',theName,true);
button.addEventListener('click',theName,true);
span.addEventListener('click',theName,true);

我们发现,执行顺序为body ——> button ——> span,为事件捕获阶段。

DOM2级规定:

  • 事件流包括三个阶段(1.捕获阶段 2.目标阶段 3.冒泡阶段)
  • 执行循序应遵循:捕获阶段 ——> 目标阶段 ——> 冒泡阶段

也就是说当你点击目标元素后,不会立刻执行触发事件,而是先执行事件捕获阶段 ——> 然后处于目标阶段(触发事件) ——> 事件冒泡阶段

我们来看一道经典面试题:当我们点击baby婴儿时的输出顺序?

html:

<body>
    <div class="grandma">grandma奶奶
        <div class="mother">mother妈妈
            <div class="daughter">daughter
                <div class="baby">baby婴儿</div>
            </div>
        </div>
    </div>
</body>

javascript:

var grandma = document.getElementsByClassName('grandma')[0]
var mother = document.getElementsByClassName('mother')[0]
var daughter = document.getElementsByClassName('daughter')[0]
var baby = document.getElementsByClassName('baby')[0]
function theName() {
    console.log('我是' + this.className);
}
baby.addEventListener('click', theName, false)//冒泡
daughter.addEventListener('click', theName, true)//捕获
mother.addEventListener('click', theName, true)//捕获
grandma.onclick = theName//冒泡

结果:

做题思路:

  • 先给绑定好事件的元素划分是 捕获?冒泡?我们可以看到daughtermother捕获babygrandma冒泡
  • 因为DOM2规定先捕获后冒泡,因此会先打印daughter和mother其中之一
  • 因为捕获是从上至下(dom根——>div),因此先打印mother后daughter
  • 因为冒泡是从下至上(div——>dom根),因此打印baby后再打印grandma

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 详解JavaScript 事件流

    事件 HTML中与javascript交互是通过事件驱动来实现的,例如鼠标点击事件.页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件.想要知道这些事件是在什么时候进行调用的,就需要了解一下"事件流"的概念. 事件流 事件流描述的就是从页面中接收事件的顺序.而早期的IE和Netscape提出了完全相反的事件流概念,IE事件流是事件冒泡,而Netscape的事件流就是事件捕获. 事件流类别 事件冒泡 即从下至上,从目标触发的元素逐级向上传播,直到win

  • JavaScript的事件流你了解吗

    目录 1. 什么是事件流 ? 2. 事件流模型 2.1) 事件冒泡 2.2) 事件捕获 3. DOM 事件流 总结 1. 什么是事件流 ? 在学习事件流之前我们先看看什么是事件 ? 事件代表文档或浏览器窗口中某个有意义的时刻 即用户与页面的交互动作(如用户点击元素时,鼠标移动到某个元素上等等) 事件的作用 JavaScript 与 HTML 的交互就是通过事件实现的 那么事件流是什么呢 ? 页面接受事件的顺序 2. 事件流模型 2.1) 事件冒泡 事件被定义为从最具体的元素(DOM 树的叶子)开

  • JS事件流与事件处理程序实例分析

    本文实例讲述了JS事件流与事件处理程序.分享给大家供大家参考,具体如下: 1.事件流:从页面中接收事件的顺序 1.1 IE :事件冒泡流 1.2 Netscape :事件捕获 1.3 DOM事件流 :事件捕获阶段--事件目标阶段--事件冒泡阶段 DOM2级事件规定 :捕获阶段不会涉及目标事件. 2.事件处理程序 事件 :用户或者浏览器自身执行的 某种动作 事件处理程序 :响应某个事件的 函数 . 2.1 HTML事件处理程序 用一个与该事件处理程序同名的HTML特性来指定. 2.1.1包含要执行

  • js事件流、事件委托与事件阶段实例详解

    目录 前言 1.事件流 2.事件处理程序 3.事件对象 4.跨浏览器事件处理 5.事件委托 总结 前言 JavaScript 与 HTML 的交互是通过事件实现的,事件代表文档或浏览器窗口中某个有意义的时刻.可以使用仅在事件发生时执行的监听器(也叫处理程序)订阅事件.本文总结一下 JS 中的事件相关知识点. 1.事件流 HTML 中与 javascript 交互是通过事件驱动来实现的,例如鼠标点击事件 onclick.页面的滚动事件 onscroll 等等,可以向文档或者文档中的元素添加事件侦听

  • 一起来学习一下JavaScript的事件流

    目录 1. 什么是事件流 ? 2. 事件流模型 2.1) 事件冒泡 2.2) 事件捕获 3. DOM 事件流 总结 1. 什么是事件流 ? 在学习事件流之前我们先看看什么是事件 ? 事件代表文档或浏览器窗口中某个有意义的时刻 即用户与页面的交互动作 (如用户点击元素时,鼠标移动到某个元素上等等) 事件的作用 JavaScript 与 HTML 的交互就是通过事件实现的 那么事件流是什么呢 ? 页面接受事件的顺序 2. 事件流模型 2.1) 事件冒泡 事件被定义为从最具体的元素(DOM 树的叶子)

  • 带你彻底搞懂JavaScript的事件流

    目录 DOM事件流 事件冒泡 事件捕获 情景一:直接在HTML中绑定事件 情景二:[domNode].onclick()方式——DOM0级 情景三:[domNode].addEventListener()方式——DOM2级 总结 DOM事件流 要明白事件流,首先我们要明白三点: 元素不是独立的,是串联在一起的 单个元素触发事件以后还会影响其他元素 事件流的方式:事件捕获(网景提出).事件冒泡(IE提出) 我们就以上图为例,假设你给div绑定了点击事件,当你点击了div后,其他元素也会受之牵连,会

  • 一文带你彻底搞懂JavaScript正则表达式

    目录 正则表达式的概述 什么是正则表达式 正则表达式的作用 正则表达式的特点 正则表达式在js中的使用 创建正则表达式 测试正则表达式 test 正则表达式中的特殊字符 正则表达式的组成 边界符 字符类 量词符 预定义类 正则表达式的替换 开发中常用正则表达式 小结 正则表达式的概述 什么是正则表达式 正则表达式( Regular Expression ) 是用于匹配字符串中字符组合的模式.在js中,正则表达式也是对象! 正则表达式的作用 正则表达式通常被用来检索.替换那些符合某个模式(规则)的

  • 一文带你搞懂JavaScript中的进制与进制转换

    目录 进制介绍 进制转换 parseInt(str, radix) Number() +(一元运算符) Number.prototype.toString(radix) 自定义转换 十进制与十六进制转换 十进制和二进制转换 进制介绍 JavaScript 中提供的进制表示方法有四种:十进制.二进制.十六进制.八进制. 对于数值字面量,主要使用不同的前缀来区分: 十进制(Decimal):取值数字 0-9:不用前缀. 二进制(Binary):取值数字 0 和 1 :前缀 0b 或 0B. 十六进制

  • 一文搞懂JavaScript中的内存泄露

    目录 什么是内存泄漏 怎么检测内存泄漏 Performance Memory 内存泄漏的场景 垃圾回收算法 引用计数 循环引用 标记清除 闭包是内存泄漏吗 总结 以前我们说的内存泄漏,通常发生在后端,但是不代表前端就不会有内存泄漏.特别是当前端项目变得越来越复杂后,前端也逐渐称为内存泄漏的高发区.本文就带你认识一下Javascript的内存泄漏. 什么是内存泄漏 什么是内存?内存其实就是程序在运行时,系统为其分配的一块存储空间.每一块内存都有对应的生命周期: 内存分配:在声明变量.函数时,系统分

  • 一文带你彻底搞懂Docker中的cgroup的具体使用

    目录 什么是cgroup cgroup的组成 cgroup提供的功能 限制cgroup中的CPU 限制cgroup中的内存 限制cgoup的进程数 前言 进程在系统中使用CPU.内存.磁盘等计算资源或者存储资源还是比较随心所欲的,我们希望对进程资源利用进行限制,对进程资源的使用进行追踪.这就让cgroup的出现成为了可能,它用来统一将进程进行分组,并在分组的基础上对进程进行监控和资源控制管理. 什么是cgroup Linux CGroup(Linux Contral Group),它其实是Lin

  • 一文搞懂JavaScript如何实现图片懒加载

    目录 实现思路 准备知识 data-* getBoundingClientRect() throttle window.innerHeight 完整代码 js部分 CSS部分 运行结果 总结 图片懒加载,往往作为减少首页白屏时间的一个解决方案而出现.直观的来说,就是不要直接加载所有图片,而是满足一定条件后才加载,也就是”惰性加载“.实现图片懒加载的方式有很多,如果要简单点那就直接使用第三方插件:vue-lazyload,如果想探究一下别人的插件是怎么实现图片懒加载的,那么可以看看本文是如何实现的

  • 一文搞懂JavaScript中bind,apply,call的实现

    目录 bind.call和apply的用法 bind call&apply 实现bind 实现call和apply 总结 bind.call和apply都是Function原型链上面的方法,因此不管是使用function声明的函数,还是箭头函数都可以直接调用.这三个函数在使用时都可以改变this指向,本文就带你看看如何实现bind.call和apply. bind.call和apply的用法 bind bind()方法可以被函数对象调用,并返回一个新创建的函数. 语法: function.bin

  • 一篇文章带你彻底搞懂VUE响应式原理

    目录 响应式原理图 编译 创建compile类 操作fragment 获取元素节点上的信息 获取文本节点信息 操作fragment 响应式 数据劫持 收集依赖 响应式代码完善 Dep类 全局watcher用完清空 依赖的update方法 需要注意的一个地方 双剑合璧 总结 首先上图,下面这张图,即为MVVM响应式原理的整个过程图,我们本篇都是围绕着这张图进行分析,所以这张图是重中之重. 响应式原理图 一脸懵逼?没关系,接下来我们将通过创建一个简单的MVVM响应系统来一步步了解这个上图中的全过程.

  • 彻底搞懂JavaScript中的apply和call方法(必看)

    call和apply都是为了改变某个函数运行的context上下文而存在的,即为了改变函数体内部this的指向.因为JavaScript的函数存在定义上下文和运行时上下文以及上下文是可以改变的概念. 回到目录定义 fun.apply(thisArg, [argsArray]) fun.call(thisArg, arg1,arg2, ...) 其中thisArg可以为null或undefined,此时表示全局对象,更详细见MDN:apply().call() 二者的作用完全一样,只是接受参数的方

  • 一篇文章搞懂JavaScript正则表达式之方法

    咱们来看看JavaScript中都有哪些操作正则的方法. RegExp RegExp 是正则表达式的构造函数. 使用构造函数创建正则表达式有多种写法: new RegExp('abc'); // /abc/ new RegExp('abc', 'gi'); // /abc/gi new RegExp(/abc/gi); // /abc/gi new RegExp(/abc/m, 'gi'); // /abc/gi 它接受两个参数:第一个参数是匹配模式,可以是字符串也可以是正则表达式:第二个参数是

随机推荐