文章目录

  • 一、事件与事件流
  • 二、事件模型
    • 1.DOM0级模型
    • 2.IE事件模型
    • 3.DOM2级模型
    • 4.DOM3级事件处理方式
  • 三、事件对象
  • 四、事件绑定与解除
    • 1.事件绑定
      • 1.1对象.on事件名字=事件处理函数
      • 1.2.对象.addEventListener("没有on的事件名字",事件处理函数,false)
      • 3.对象.attachEvent("有on的事件名字",事件处理函数);
    • 2.解除绑定
  • 五、Event Wrapper
  • 六、自定义事件
  • 七、JQuery Event模型
  • 八、JS事件模型-观察者模式
  • 九、代码例子(通用事件绑定&事件冒泡&代理)
    • 1. 通用事件绑定
    • 2.事件冒泡
    • 3.代理
    • 附加节点操作

一、事件与事件流

事件是与浏览器或文档交互的瞬间,如点击按钮,填写表格等,它是JS与HTML之间交互的桥梁。
DOM是树形结构,如果同时给父子节点都绑定事件时,当触发子节点的时候,这两个事件的发生顺序如何决定?这就涉及到事件流的概念,它描述的是页面中接受事件的顺序。

事件流有两种:

  • 事件冒泡(Event Capturing): 是一种从下往上的传播方式。事件最开始由最具体的元素(文档中嵌套层次最深的那个节点接受, 也就是DOM最低层的子节点), 然后逐渐向上传播到最不具体的那个节点,也就是DOM中最高层的父节点。
  • 事件捕获(Event Bubbling): 与事件冒泡相反。事件最开始由不太具体的节点最早接受事件, 而最具体的节点最后接受事件。

顺序:
捕获阶段-目标阶段-冒泡阶段
同时绑定事件捕获和事件冒泡,会先执行事件捕获。

二、事件模型

  • DOM0就是直接通过 onclick写在html里面的事件;
  • DOM2是通过addEventListener绑定的事件, 还有IE下的DOM2事件通过attachEvent绑定;
  • DOM3是一些新的事件。

1.DOM0级模型

又称为原始事件模型,在该模型中,事件不会传播,即没有事件流的概念。事件绑定监听函数比较简单, 有两种方式:

  1. HTML代码中直接绑定:
<input type="button" onclick="fun()">
  1. 通过JS代码指定属性值:
var btn = document.getElementById('.btn');
btn.onclick = fun;

移除监听函数:

btn.onclick = null;

这种方式所有浏览器都兼容,但是逻辑与显示并没有分离。

2.IE事件模型

IE事件模型共有两个过程:

  • 事件处理阶段(target phase)。事件到达目标元素, 触发目标元素的监听函数。

  • 事件冒泡阶段(bubbling phase)。事件从目标元素冒泡到document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行。

事件绑定监听函数的方式如下:

attachEvent(eventType, handler)

事件移除监听函数的方式如下:

detachEvent(eventType, handler)

参数说明:

  • eventType指定事件类型(注意加on)

  • handler是事件处理函数
    例子:

var btn = document.getElementById('.btn');
btn.attachEvent(‘onclick’, showMessage);
btn.detachEvent(‘onclick’, showMessage);

3.DOM2级模型

属于W3C标准模型,现代浏览器(除IE6-8之外的浏览器)都支持该模型。在该事件模型中,一次事件共有三个过程:

  • 事件捕获阶段(capturing phase)。事件从document一直向下传播到目标元素, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行。

  • 事件处理阶段(target phase)。事件到达目标元素, 触发目标元素的监听函数。

  • 事件冒泡阶段(bubbling phase)。事件从目标元素冒泡到document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行。

事件绑定监听函数的方式如下:

addEventListener(eventType, handler, useCapture)

事件移除监听函数的方式如下:

removeEventListener(eventType, handler, useCapture)

参数说明:

  • eventType指定事件类型(不要加on)
  • handler是事件处理函数
  • useCapture是一个boolean用于指定是否在捕获阶段进行处理,一般设置为false与IE浏览器保持一致。(默认false冒泡)

例子:

var btn = document.getElementById('.btn');
btn.addEventListener(‘click’, showMessage, false);
btn.removeEventListener(‘click’, showMessage, false);

4.DOM3级事件处理方式

DOM浏览器中可能发生的事件有很多种不同事件类型具有不同的信息DOM3级事件规定了一下几种事件

  • UI事件当用户与页面上的元素交互时触发
  • 焦点事件当元素获得或者失去焦点时触发
  • 鼠标事件当用户通过鼠标在页面上执行操作时触发
  • 滚轮事件当使用鼠标滚轮或类似设备时触发
  • 文本事件当在文档中输入文本时触发
  • 键盘事件当用户通过键盘在页面上执行操作时触发
  • 合成事件当为IMEInput Method Editor输入法编辑器输入字符时触发
  • 变动事件当底层Dom结构发生变化时触发

DOM3级事件模块在DOM2级事件的基础上重新定义了这些事件也添加了一些新事件。包括IE9在内的主流浏览器都支持DOM2级事件IE9也支持DOM3级事件。

DOM中的事件模拟自定义事件

DOM3级还定义了自定义事件自定义事件不是由DOM原生触发的它的目的是让开发人员创建自己的事件。要创建的自定义事件可以由createEvent(“CustomEvent”);

返回的对象有一个initCustomEvent方法接收如下四个参数。

  • type字符串触发的事件类型自定义。例如 “keyDown”“selectedChange”;

  • bubble布尔值标示事件是否应该冒泡

  • cancelable(布尔值)标示事件是否可以取消

  • detail对象任意值保存在event对象的detail属性中

后面详细介绍。

三、事件对象

当一个事件被触发时,会创建一个事件对象(Event Object), 这个对象里面包含了与该事件相关的属性或者方法。该对象会作为第一个参数传递给监听函数。

DOM事件模型中的事件对象常用属性:

  • type用于获取事件类型
  • target获取事件目标
  • stopPropagation()阻止事件冒泡
  • preventDefault()阻止事件默认行为

IE事件模型中的事件对象常用属性:

  • type用于获取事件类型
  • srcElement获取事件目标
  • cancelBubble阻止事件冒泡
  • returnValue阻止事件默认行为

四、事件绑定与解除

1.事件绑定

1.1对象.on事件名字=事件处理函数

缺点:如果绑定多个事件,前面的事件会被后面的事件覆盖

document.getElementById("btn").onclick = function () {console.log("第一");};

1.2.对象.addEventListener(“没有on的事件名字”,事件处理函数,false)

解释:第三个参数在本篇文章的事件阶段中有解释,false:冒泡; true:捕获

优点:可以绑定多个事件

缺点:谷歌和火狐支持,IE8不支持

document.getElementById("btn").addEventListener("click", function () {console.log("第一");}, false);//false冒泡阶段(默认),true捕获阶段

3.对象.attachEvent(“有on的事件名字”,事件处理函数);

优点:可以绑定多个事件

缺点:谷歌和火狐不支持,IE8支持

document.getElementById("btn").attachEvent("onclik", function () {console.log("第一");});

2.解除绑定

用什么方式绑定事件,就应该用对应的方式解绑事件
1.解绑事件

对象.on事件名字=事件处理函数--->绑定事件
对象.on事件名字=null;

2.解绑事件

对象.addEventListener("没有on的事件类型",命名函数,false);---绑定事件
对象.removeEventListener("没有on的事件类型",函数名字,false);

3.解绑事件

对象.attachEvent("on事件类型",命名函数);---绑定事件
对象.detachEvent("on事件类型",函数名字);

五、Event Wrapper

由于事件模型的差异以及Event对象的不同,为了达到兼容各个浏览器的目的,我们可以增加一个Event Wrapper, 它对各个浏览器应当提供一致的事件操作接口。

var eventUtils={// 添加句柄addHandler:function(element,type,handler){if(element.addEventListener){element.addEventListener(type,handler,false);}else if(element.attachEvent){element.attachEvent('on'+type,handler);}else{element['on'+type]=handler;}},// 删除句柄removeHandler:function(element,type,handler){if(element.removeEventListener){element.removeEventListener(type,handler,false);}else if(element.detachEvent){element.detachEvent('on'+type,handler);}else{element['on'+type]=null;}},//获取事件对象//IE模型中event是一个全局唯一的对象绑定在window对象上getEvent:function(event){return event?event:window.event;},//获取类型getType:function(event){return event.type;},getElement:function(event){return event.target || event.srcElement;},//阻止默认事件preventDefault:function(event){if(event.preventDefault){event.preventDefault();}else{event.returnValue=false;}},//阻止冒泡stopPropagation:function(event){if(event.stopPropagation){event.stopPropagation();}else{event.cancelBubble=true;}}}

六、自定义事件

JS中已经内置了很多事件,如click, mouseover等等,但是内置事件毕竟有限,有时候我们想自己定义一些事件,例如三连击,threeclick。如何实现自定义事件呢?

  1. 首先要创建一个事件。可以使用以下方式:
var event = new Event('threeclick', {"bubbles":true, "cancelable":false});
  • bubbles表示该事件是否冒泡。
  • cancelable表示该事件能否被取消。
  1. 然后我们需要为事件注册监听函数:
target.addEventListener('threeclick', hello, false);
  1. 最后我们要在合适的时机触发该事件,我们可以使用dispatchEvent函数。该方法在当前节点触发指定事件,从而触发监听函数执行。该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault(), 则返回false, 否则返回true。
target.dispatchEvent(event);

七、JQuery Event模型

JQuery解决的一个主要问题就是浏览器的兼容问题,它有自己的事件模型实现方式。它主要有以下特性:

  • 重定义了JQuery.Event对象, 统一了事件属性和方法, 统一了事件模型
  • 可以在一个事件类型上添加多个事件处理函数, 可以一次添加多个事件类型的事件处理函数
  • 支持自定义事件(事件命名空间)
  • 提供了toggle, hover组合事件
  • 提供了one, live-die, delegate-undelegate
  • 提供了统一的事件封装, 绑定, 执行, 销毁机制
  • $(document).ready();

八、JS事件模型-观察者模式

观察者模式又叫做发布订阅者模式(Publish/Subscribe),它可以让多个观察者对象同时监听某一个主题对象,这个主题对象的状态变化时会通知所有的订阅者,使得它们能够做出反应。
JS的事件模型就是一种观察者模式的体现,当对应的事件被触发时,监听该事件的所有监听函数都会被调用。

用JS实现的一个观察者模式的代码:

var events = (function() {var topics = {};return {publish: function(topic, info) {console.log('publish a topic:' + topic);if (topics.hasOwnProperty(topic)) {topics[topic].forEach(function(handler) {handler(info ? info : {});})}},subscribe: function(topic, handler) {console.log('subscribe an topic:' + topic);if (!topics.hasOwnProperty(topic)) {topics[topic] = [];}topics[topic].push(handler);},remove: function(topic, handler) {if (!topics.hasOwnProperty(topic)) {return;}var handlerIndex = -1;topics[topic].forEach(function(element, index) {if (element === handler) {handlerIndex = index;}});if (handlerIndex >= 0) {topics[topic].splice(handlerIndex, 1);}},removeAll: function(topic) {console.log('remove all the handler on the topic:' + topic);if (topics.hasOwnProperty(topic)) {topics[topic].length = 0;}}}
})();

使用:

//主题监听函数
var handler = function(info) {console.log(info);
}
//订阅hello主题
events.subscribe('hello', handler);//发布hello主题
events.publish('hello', 'hello world');

九、代码例子(通用事件绑定&事件冒泡&代理)

1. 通用事件绑定

//原本的
var btn = document.getElementById('btn1');
btn.addEventListener('click',function(event){console.log('clicked');
})//封装的    如addEventListener 就不用重复写,不然太长了影响压缩,占用带宽
function bindEvent(elem,type,fn){elem.addEventListener(type,fn);
}
//使用
var a = document.getElementById('link1');
bindEvent(a,'click',function(e){e.preventDefault(); //阻止默认行为,如a标签跳转alert(clicked);
})

完善通用绑定事件的函数(添加代理)

function bindEvent(elem,type,selector,fn){if(fn == null){//没传入代理fn = selector;xselector = null;}elem.addEventListener(type,function(e){var target;if(selector){//如果存在代理target = e.target;  //target事件属性可返回事件的目标节点(触发该事件的节点)if(target.matches(selector)){ //判断是否满足这个选择器fn.call(target,e)}}else{fn(e);}})
}//使用代理  好处:代码简洁,减少浏览器内存占用
var div1 = document.getElementById('div1');
bindEvent(div1,'click','a',function(e){console.log(this.innerHTML); //此处的this是a
});

2.事件冒泡

点击p1为激活,点击其他为取消,用了冒泡不用挨着添加取消的点击事件了

 <body><div id="div1"><p id="p1">激活</p><p id="p2">取消</p><p id="p3">取消</p><p id="p4">取消</p></div><div id="div2"><p id="p5">取消</p><p id="p6">取消</p></div></body>var p1 = document.getElementById('p1');var body = document.body;bindEvent(p1,'click',function(e){e.stopPropatation();  // 阻止冒泡,就不会再触发body上的取消事件了;alert('激活');})bindEvent(body,'click',function(e){alert('取消')})//封装的    如addEventListener 就不用重复写,不然太长了影响压缩,占用带宽function bindEvent(elem,type,fn){elem.addEventListener(type,fn);}

3.代理

 <div id="div1"><a href="#">a1</a><a href="#">a2</a><a href="#">a3</a><a href="#">a4</a><!-- 会随时新增更多的 a标签 -->
</div>var div1 = document.getElementById('div1');
div1.addEventListener('click',function(e){var target = e.target;if(target.nodeName === 'A'){alert(target.innerHTML);}
})

附加节点操作

  • document.getElementById();//id名,在实际开发中较少使用,选择器中多用class id一般只用在顶级层存在 不能太过依赖id

  • document.getElementsByTagName();//标签名

  • document.getElementsByClassName();//类名

  • document.getElementsByName();//name属性值,一般不用

  • document.querySelector();//css选择符模式,返回与该模式匹配的第一个元素,结果为一个元素;如果没找到匹配的元素,则返回null

  • document.querySelectorAll()//css选择符模式,返回与该模式匹配的所有元素,结果为一个类数组

  • parentNode//获取所选节点的父节点,最顶层的节点为#document

  • childNodes //获取所选节点的子节点们

  • firstChild //获取所选节点的第一个子节点

  • lastChild //获取所选节点的最后一个子节点

  • nextSibling //获取所选节点的后一个兄弟节点 列表中最后一个节点的nextSibling属性值为null

  • previousSibling //获取所选节点的前一兄弟节点 列表中第一个节点的previousSibling属性值为null

参考:https://segmentfault.com/a/1190000006934031

本文链接:https://blog.csdn.net/qq_39903567/article/details/115281827

JS基础-事件模型(事件事件流自定义事件事件冒泡/代理)相关推荐

  1. 事件模型、事件流(冒泡与捕获)、事件代理

    本文原链接:https://www.cnblogs.com/hngdlxy143/p/9068282.html https://www.jb51.net/article/139997.htm 事件模型 ...

  2. 行为模型实例 php,JS中事件模型的实例详解

    之前对事件模型还是比较清楚的,许多概念都清晰映射在脑海中.工作之后,一方面使用的 局限性,二是习惯于用框架中的各种事件监听方式,简单即方便,久而久之,事件的一些概念开 始淡出记忆中,就像我现在已经开始 ...

  3. 12.在JavaScript中的事件模型如何理解?

    一.事件与事件流 javascript中的事件,可以理解就是在HTML文档或者浏览器中发生的一种交互操作,使得网页具备互动性, 常见的有加载事件.鼠标事件.自定义事件等 由于DOM是一个树结构,如果在 ...

  4. JavaScript 事件模型 事件处理机制

    这篇文章对于了解Javascript的事件处理机制非常好,将它全文转载于此,以备不时之需. 什么是事件? 事件(Event)是JavaScript应用跳动的心脏 ,也是把所有东西粘在一起的胶水.当我们 ...

  5. javascript中0级DOM和2级DOM事件模型浅析

    Javascript程序使用的是事件驱动的设计模式,为一个元素添加事件监听函数,当这个元素的相应事件被触发那么其添加的事件监听函数就被调用: <input type="button&q ...

  6. 标准事件模型和IE事件模型

    前言:在上一篇博客中总结了0级DOM事件模型和2级DOM事件模型,打铁趁热就在谈谈标准事件模型和IE事件模型的区别吧. 一. 标准事件模型 在JavaScript中把标准事件模型的执行分为三个阶段,即 ...

  7. 浏览器事件模型与jquery事件

    首先看一下浏览器事件模型: 可见,浏览器在解析时候,要过两遍HTML,一次是从上而下,称为事件捕获:一次从下而上,称为事件冒泡(关于事件冒泡和事件捕获,这里就不详细说了). 停止冒泡的方式:e.sto ...

  8. 回调函数与Delphi的事件模型

    回调函数: 回调函数是这样一种机制:调用者在初始化一个对象(这里的对象是泛指,包括OOP中的对象.全局函数等)时,将一些参数传递给对象,同时将一个调用者可以访问的函数地址传递给该对象.这个函数就是调用 ...

  9. Visual Studio 中指定自定义生成事件

    自定义生成事件打开方式 通过指定自定义生成事件,可以在生成开始之前或在它完成之后自动运行命令.在Visual Studio中通过右键项目->属性 进入项目属性菜单. 自定义生成事件的语法 生成事 ...

  10. 分类-3-生成学习-3-朴素贝叶斯模型、laplace平滑、多元伯努利事件模型、多项式事件模型

    参考 http://www.cnblogs.com/jerrylead 多元伯努利事件模型( multi-variate Bernoulli event model) 在 GDA 中,我们要求特征向量 ...

最新文章

  1. python读取红外图
  2. JAVA NIO知识点总结(2)——直接缓冲区和非直接缓冲区
  3. 【CF 1195】Basketball Exercise/Submarine in the Rybinsk Sea (hard edition)/OpenStreetMap+二维单调队列滑动窗口模板
  4. [vue] vue的is这个特性你有用过吗?主要用在哪些方面?
  5. JAVA多线程--线程阻塞与唤醒
  6. SVD奇异值分解(PCA,LSI)
  7. Youki的装机日记~
  8. Eclipse自己定义keystore
  9. 数据库和数据库实例的概念
  10. 三层交换机如何实现不同网络的相互通信
  11. 2.7 SLD参考标准与GeoServer扩展
  12. SDUT——2021级-JAVA02 基础语法1--标识符、常量与变量、数据类型、运算符与表达式
  13. java project 显示感叹号_项目工程上有感叹号或者差号
  14. java version什么意思_输入java -version命令后提示结果如下,是什么意思??哪位能看懂,在线等。。。。...
  15. 南邮——计算机图像学——光照、冯氏光照模型
  16. 大数据技术之Hadoop3.x
  17. blog.csdn.net/carson2005
  18. 专家解读:读研到底值不值(转自中华英才网)
  19. oracle删除字段速度,oracle删除字段
  20. mysql 分区表 range

热门文章

  1. blender用视频做背景渲染动画节点设置
  2. 在格式化字符串的边缘试探
  3. MyCP.java蓝墨云班课
  4. 团队的英文翻译缩写_团队的英语是什么?简写呢?
  5. 机器学习——优化算法:牛顿法-伪代码描述算法
  6. excel 文件加密
  7. 内行人看笑话 外行人一脸懵逼
  8. 数据库 SQL 语句学习
  9. excel单元格数字拆分比较
  10. Android TextView 字体 加粗以及判断是否加粗