我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JS浏览器事件模型的示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JS浏览器事件模型的示例分析

小编给大家分享一下JS浏览器事件模型的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

JavaScript的特点

1.JavaScript主要用来向HTML页面添加交互行为。2.JavaScript可以直接嵌入到HTML页面,但写成单独的js文件有利于结构和行为的分离。3.JavaScript具有跨平台特性,在绝大多数浏览器的支持下,可以在多种平台下运行。

什么是事件

我想你很可能听说过事件驱动, 但是事件驱动到底是什么?为什么说浏览器是事件驱动的呢?

事件驱动通俗地来说就是什么都抽象为事件。

  • 一次点击是一个事件

  • 键盘按下是一个事件

  • 一个网络请求成功是一个事件

  • 页面加载是一个事件

  • 页面报错是一个事件

浏览器依靠事件来驱动APP运行下去,如果没有了事件驱动,那么APP会直接从头到尾运行完,然后结束,事件驱动是浏览器的基石。

一个简单的例子

其实现实中的红绿灯就是一种事件,它告诉我们现在是红灯状态,绿灯状态,还是黄灯状态。 我们需要根据这个事件自己去完成一些操作,比如红灯和黄灯我们需要等待,绿灯我们可以过马路。

下面我们来看一个最简单的浏览器端的事件:

html代码:

<button>Change color</button>

js代码:

var btn = document.querySelector('button');btn.onclick = function() {  console.log('button clicked')}

代码很简单,我们在button上注册了一个事件,这个事件的handler是一个我们定义的匿名函数。当用户点击了这个被注册了事件的button的时候,这个我们定义好的匿名函数就会被执行。

如何绑定事件

我们有三种方法可以绑定事件,分别是行内绑定,直接赋值,用addEventListener。

内联这个方法非常不推荐

html代码:

<button onclick="handleClick()">Press me</button>

然后在script标签内写:

function handleClick() {  console.log('button clicked')}

直接赋值

和我上面举的例子一样:

var btn = document.querySelector('button');btn.onclick = function() {  console.log('button clicked')}

这种方法有两个缺点

不能添加多个同类型的handler

btn.onclick = functionA;btn.onclick = functionB;

这样只有functionB有效,这可以通过addEventListener来解决。

不能控制在哪个阶段来执行,这个会在后面将事件捕获/冒泡的时候讲到。这个同样可以通过addEventListener来解决。

因此addEventListener横空出世,这个也是目前推荐的写法。

addEventListener

旧版本的addEventListener第三个参数是bool,新版版的第三个参数是对象,这样方便之后的扩展,承载更多的功能, 我们来重点介绍一下它。

addEventListener可以给Element,Document,Window,甚至XMLHttpRequest等绑定事件,当指定的事件发生的时候,绑定的回调函数就会被以某种机制进行执行,这种机制我们稍后就会讲到。

语法:

target.addEventListener(type, listener[, options]);target.addEventListener(type, listener[, useCapture]);target.addEventListener(type, listener[, useCapture, wantsUntrusted  ]); // Gecko/Mozilla only

type是你想要绑定的事件类型,常见的有click, scroll, touch, mouseover等,旧版本的第三个参数是bool,表示是否是捕获阶段,默认是false,即默认为冒泡阶段。新版本是一个对象,其中有capture(和上面功能一样),passive和once。 once用来执行是否只执行一次,passive如果被指定为true表示永远不会执行preventDefault(),这在实现丝滑柔顺的滚动的效果中很重要。更多请参考Improving scrolling performance with passive listeners

框架中的事件

实际上,我们现在大多数情况都是用框架来写代码,因此上面的情况其实在现实中是非常少见的,我们更多看到的是框架封装好的事件,比如react的合成事件,感兴趣的可以看下这几篇文章。

  • React SyntheticEvent

  • Vue和React的优点分别是什么?两者的最核心差异对比是什么?

虽然我们很少时候会接触到原生的事件,但是了解一下事件对象,事件机制,事件代理等还是很有必要的,因为框架的事件系统至少在这方面还是一致的,这些内容我们接下来就会讲到。

事件对象

所有的事件处理函数在被浏览器执行的时候都会带上一个事件对象,举个例子:

function handleClick(e) {  console.log(e);}  btn.addEventListener('click', handleClick);

这个e就是事件对象,即event object。 这个对象有一些很有用的属性和方法,下面举几个常用的属性和方法。

属性

  • target

  • x, y等位置信息

  • timeStamp

  • eventPhase

方法

  • preventDefault 用于阻止浏览器的默认行为,比如a标签会默认进行跳转,form会默认校验并发送请求到action指定的地址等

  • stopPropagation 用于阻止事件的继续冒泡行为,后面讲事件传播的时候会提到。

事件传播

前面讲到了事件默认是绑定到冒泡阶段的,如果你显式令useCapture为true,则会绑定到捕获阶段。

事件捕获很有意思,以至于我会经常出事件的题目加上一点事件传播的机制,让候选人进行回答,这很能体现一个人的水平。了解事件的传播机制,对于一些特定问题有着非常大的作用。

一个Element上绑定的事件触发了,那么其实会经过三个阶段。

第一个阶段 - 捕获阶段

从最外层即HTML标签开始,检查当前元素有没有绑定对应捕获阶段事件,如果有则执行,没有则继续往里面传播,这个过程递归执行直到触达触发这个事件的元素为止。

伪代码:

function capture(e, currentElement) {    if (currentElement.listners[e.type] !== void 0) {        currentElement.listners[e.type].forEach(fn => fn(e))    }    // pass down    if (currentElement !== e.target) {        // getActiveChild用于获取当前事件传播链路上的子节点        capture(e, getActiveChild(currentElement, e))    } else {        bubble(e, currentElement)    }}// 这个Event对象由引擎创建capture(new Event(), document.querySelector('html'))

第二个阶段 - 目标阶段

上面已经提到了,这里省略了。

第三个阶段 - 冒泡阶段

从触发这个事件的元素开始,检查当前元素有没有绑定对应冒泡阶段事件,如果有则执行,没有则继续往里面传播,这个过程递归执行直到触达HTML为止。

伪代码:

function bubble(e, currentElement) {    if (currentElement.listners[e.type] !== void 0) {        currentElement.listners[e.type].forEach(fn => fn(e))    }    // returning    if (currentElement !== document.querySelector('html')) {        bubble(e, currentElement.parent)    }}

上述的过程用图来表示为:

JS浏览器事件模型的示例分析

如果你不希望事件继续冒泡,可以用之前我提到的stopPropagation。

伪代码:

function bubble(e, currentElement) {    let stopped = false;    function cb() {        stopped = true;    }    if (currentElement.listners[e.type] !== void 0) {        currentElement.listners[e.type].forEach(fn => {            fn({                ...e,                stopPropagation: cb            });            if (stopped) return;        })    }    // returning    if (currentElement !== document.querySelector('html')) {        bubble(e, currentElement.parent)    }}

事件代理

利用上面提到的事件冒泡机制,我们可以选择做一些有趣的东西。 举个例子:

我们有一个如下的列表,我们想在点击对应列表项的时候,输出是点击了哪个元素。

HTML代码:

<ul>    <li>1</li>    <li>2</li>    <li>3</li>    <li>4</li></ul>

JS代码:

document.querySelector('ul').addEventListener('click', e => console.log(e.target.innerHTML))

在线地址,上面说了addEventListener会默认绑定到冒泡阶段,因此事件会从目标阶段开始,向外层冒泡,到我们绑定了事件的ul上,ul中通过事件对象的target属性就能获取到是哪一个元素触发的。

“事件会从目标阶段开始”,并不是说事件没有捕获阶段,而是我们没有绑定捕获阶段,我描述给省略了。

我们只给外层的ul绑定了事件处理函数,但是可以看到li点击的时候,实际上会打印出对应li的内容(1,2,3或者4)。 我们无须给每一个li绑定事件处理函数,不仅从代码量还是性能上都有一定程度的提升。

这个有趣的东西,我们给了它一个好听的名字“事件代理”。在实际业务中我们会经常使用到这个技巧,这同时也是面试的高频考点。

总结

事件其实不是浏览器特有的,和JS语言也没有什么关系,这也是我为什么没有将其划分到JS部分的原因。很多地方都有事件系统,但是各种事件模型又不太一致。

我们今天讲的是浏览器的事件模型,浏览器基于事件驱动,将很多东西都抽象为事件,比如用户交互,网络请求,页面加载,报错等,可以说事件是浏览器正常运行的基石。

我们在使用的框架都对事件进行了不同程度的封装和处理,除了了解原生的事件和原理,有时候了解一下框架本身对事件的处理也是很有必要的。

当发生一个事件的时候,浏览器会初始化一个事件对象,然后将这个事件对象按照一定的逻辑进行传播,这个逻辑就是事件传播机制。 我们提到了事件传播其实分为三个阶段,按照时间先后顺序分为捕获阶段,目标阶段和冒泡阶段。开发者可以选择监听不同的阶段,从而达到自己想要的效果。

事件对象有很多属性和方法,允许你在事件处理函数中进行读取和操作,比如读取点击的坐标信息,阻止冒泡等。

最后我们通过一个例子,说明了如何利用冒泡机制来实现事件代理。

以上是“JS浏览器事件模型的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JS浏览器事件模型的示例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

JS浏览器事件模型的示例分析

小编给大家分享一下JS浏览器事件模型的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!JavaScript的特点1.JavaScript主要用来向HTML页
2023-06-15

浏览器User-Agent的示例分析

浏览器User-Agent的示例分析,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一、基础知识篇:Http Header之User-AgentUser Agent中文名为用
2023-06-08

浏览器渲染的示例分析

这篇文章将为大家详细讲解有关浏览器渲染的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。浏览器渲染1.浏览器渲染图解浏览器渲染页面主要经历了下面的步骤:1.处理 HTML 标记并构建 DOM 树。2
2023-06-15

js对象和事件的示例分析

这篇文章给大家分享的是有关js对象和事件的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1.内置对象1.1 String1.2Math1.3Date说明2.对象2.1 对象的创建JS创建自定义对象,主要通
2023-06-29

js事件流、事件委托与事件阶段的示例分析

这篇文章主要介绍了js事件流、事件委托与事件阶段的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1、事件流HTML 中与 javascript 交互是通过事件驱动来实
2023-06-29

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录