资讯专栏INFORMATION COLUMN

【重温基础】20.事件

Blackjun / 1437人阅读

摘要:本文是重温基础系列文章的第二十篇。事件捕获为截获事件提供机会,然后实际的目标接收到事件,最后事件冒泡,对事件作出响应。事件处理事件处理,即响应某个事件。包括导致事件的元素事件类型等其他信息。

本文是 重温基础 系列文章的第二十篇。

这是第三个基础系列的第一篇,欢迎持续关注呀!
重温基础 系列的【初级】和【中级】的文章,已经统一整理到我的【Cute-JavaScript】的JavaScript基础系列中。

今日感受:电影有时候看的是缘分。

系列目录:

【复习资料】ES6/ES7/ES8/ES9资料整理(个人整理)

【重温基础】1-14篇

【重温基础】15.JS对象介绍

【重温基础】16.JSON对象介绍

【重温基础】17.WebAPI介绍

【重温基础】18.相等性判断

【重温基础】19.闭包

本章节复习的是JS中的事件,事件冒泡捕获代理模拟等等。

前置知识:
JavaScript与HTML的交互式通过事件来实现的,是文档或浏览器窗口中发生的一些特定的交互瞬间。

1.事件流

事件流描述的是从页面中接收事件的顺序,通常有这样两种完全相反的事件流概念:事件冒泡流(IE团队提出)和事件捕获流(网景团队提出)。

1.1 事件冒泡

冒泡事件(Event Bubbling):事件开始时由最具体的元素接收(文档中嵌套层次最深的那个节点),然后逐层向上传播到较为不具体的节点(文档),看下示例代码:




    leo 事件冒泡


    
点击

点击页面中

元素,这个click事件就会按照下面顺序传播:

document

由此可见,元素绑定的事件会通过DOM树向上传播,每层节点都会发生,直到document对象,如图展示了冒泡过程:

1.2 事件捕获

事件捕获(Event Capturing):让不太具体的节点更早接收事件,而最具体的节点最后接收事件,即在事件到达预定目标之前捕获到,看下示例代码(HTML代码和前面一样),事件捕获的过程是这样的:

document

看得出,document对象最新接收事件,然后沿DOM树依次向下,直到最后的实际目标

元素,如图展示了捕获过程:

注意:由于老版本的浏览器不支持,因此很少人使用事件捕获,不过如果特殊需求还是可以使用事件捕获,建议还是使用事件冒泡。

1.3 DOM事件流

“DOM2级事件”规定的事件流包含三个阶段:事件捕获阶段处于目标阶段事件冒泡阶段
事件捕获为截获事件提供机会,然后实际的目标接收到事件,最后事件冒泡,对事件作出响应。按照前面的HTML代码,整个流程是这样的:

在DOM事件流中,实际目标(

元素)在捕获阶段不接收事件,即在捕获阶段,事件从document对象再到后就停止,进入“处于目标”阶段,事件在
元素上发生,然后才进入冒泡阶段,将事件传回给文档。

注意:目前主流浏览器都支持DOM事件流,只有IE8和之前版本不支持。

2.事件处理

事件处理,即响应某个事件。我们把事件处理的函数,称为“事件处理程序”。
事件处理程序的名称一般都以on开头,如click事件的事件处理程序就是onclickload事件的事件处理程序就是onload
我们将事件处理程序,分为这么几类:

HTML事件处理程序

DOM0级事件处理程序

DOM2级事件处理程序

IE事件处理程序

跨浏览器事件处理程序

2.1 HTML事件处理程序

某个元素支持的事件,都可以用一个与相应事件处理程序同名的HTML特性来指定,这个特性的值应该是能够执行的JavaScript代码。比如:

也可以把需要执行的具体事件多带带定义出来,可以放置与多带带.js文件,也可以在文档内用

我们可以使用event中的对象和方法:

阻止事件的默认行为

var leo = document.getElementById("leo");
leo.onclick = function(event){
    // 只有当 event 中的 cancelable 属性为true的事件
    event.preventDefault();
}

立即停止事件在DOM的传播

通过调用event.stopPropagation()方法避免弹框出现两次。

var leo = document.getElementById("leo");
leo.onclick = function(event){
    alert("leo");
    event.stopPropagation();
}
document.body.onclick = function(event){
    alert("hello leo");
}
3.2 IE中的事件对象

访问IE中的事件对象event,方法有多种,取决于事件处理程序的方法:

DOM0级方法,使用window.event

var leo = document.getElementById("leo");
leo.onclick = function(){
    var event = window.event;
    alert(event.type);   // "click"
}

IE的attachEvent方法,event作为参数传入(也可以使用window.event

var leo = document.getElementById("leo");
leo.attachEvent("onclick",function(event){
    alert(event.type);   // "click"
},false);
3.3 跨浏览器的事件对象

虽然DOM和IE中event对象不同,但我们也可以和前面的 跨浏览器事件处理程序 处理一样,通过他们之间的区别,实现映射:

var my_event = {
    myAddFun : function(element, type, handler){
        // do some thing
    },
    // 返回对event的引用
    getMyEvent : function(event){
        return event?event:window.event;
    },
    // 返回事件的目标
    getMyTarget : function(event){
        return event.target || event.srcElement;
    },
    // 取消事件的默认行为
    preventDefault : function(event){
        if(event.preventDefault){
            event.preventDefault();
        }else {
            event.returnValue = false;
        }
    },

    myRemoveFun : function(element, type, handler){
        // do some thing
    },

    // 阻止事件流
    stopPropagetion : function(event){
        if(event.stopPropagetion){
            event.stopPropagetion();
        }else {
            event.cancelBubble = true;
        }
    }
}

var leo = document.getElementById("leo");
leo.onclick = function(event){
    alert("leo");
    event = my_event(event);
    my_event.stopPropagation(event);
}

leo.onclick = function(event){
    alert("hello world");
}
4.事件类型

Web浏览器中的事件类型有很多,DOM3级事件规定有以下几类事件类型:

UI事件:当用户与页面上元素交互时触发;

焦点事件:当元素失去或获取焦点时触发;

鼠标事件:当用户通过鼠标在页面操作时触发;

滚轮事件:当使用鼠标滚轮(或类似设备)时触发;

文本事件:当在文档中输入文本时触发;

键盘事件:当用户通过键盘操作时触发;

合成事件:当为IME输入字符时触发;

变动事件:当底层DOM结构变动时触发;

具体每个方法的详细介绍,可以查看W3school HTML DOM Event 对象
或者查看《JavaScript高级程序设计(第三版)》的第362页开始。
我后面会多带带整理一篇,介绍这些事件的文章。

5.事件委托

简单理解就是讲一个响应事件委托到另一个元素。
事件委托利用事件冒泡,指定一个事件处理程序来管理某一类型的所有事件,比如我们通过一个函数来代替其他三个函数:

  • 按钮1
  • 按钮2
  • 按钮3
var btn1 = document.getElementById("btn1");
var btn2 = document.getElementById("btn2");
var btn3 = document.getElementById("btn3");
// my_event 在前面定义了
my_event.myAddFun(btn1, "click", function(event){
    alert("btn1点击");
});
my_event.myAddFun(btn2, "click", function(event){
    alert("btn2点击");
});
my_event.myAddFun(btn3, "click", function(event){
    alert("btn3点击");
});

下面我们在DOM树层级更高的元素上添加一个事件处理函数,来做事件委托,我们这么重写这段代码:

var btn = document.getElementById("btn");
my_event.myAddFun(btn, "click", function(event){
    event = my_event.getMyEvent(event);
    var target = my_event.getMyTarget(event);
    switch(target.id){
        case "btn1":
            alert("btn1点击");
            break;
        case "btn2":
            alert("btn2点击");
            break;
        case "btn3":
            alert("btn3点击");
            break;
    }
});

最适合采用事件委托技术的事件包括:click/mousedown/mouseup/keyup/keydown/keypress,虽然mouseovermouseout事件也有冒泡,但因为不好处理它们并且经常需要重新计算元素位置。

可以看出,事件委托有以下优点:

减少内存消耗

动态绑定事件

6.事件模拟

JavaScript的事件模拟主要用来在任意时刻触发特定事件。

6.1 DOM中的事件模拟

document对象上使用createEvent()方法创建一个event对象。
createEvent()接收一个参数,即要创建的事件类型的字符串。
DOM2级中,所有这些字符串都使用英文复数形式,DOM3级中都变成单数,也可以是下面中的字符串:

UIEvents : 一般化的UI事件(鼠标和键盘事件都继承自UI事件)(DOM3级中UIEvent

MouseEvents : 一般化的鼠标事件(DOM3级中MouseEvent

MutationEvents : 一般化的DOM滚动事件(DOM3级中MutationEvent

HTMLEvents : 一般化的HTML事件(DOM3级中HTMLEvent

创建event之后,我们需要使用dispatchEvent()方法去触发这个事件,需要传入一个参数,参数是需要触发事件的event对象。

所有支持事件的DOM节点都支持这个方法。事件触发之后,事件就能照样冒泡并引发响应事件处理程序的执行。

6.1.1 模拟鼠标事件

使用createEvent()方法传入MouseEvents创建一个鼠标事件,返回的对象有一个initMouseEvent()方法,用于指定与该鼠标事件相关的信息,有15个参数:

type : 字符串,表示触发的事件类型,如click

bubble : 布尔值,表示是否冒泡,为了精确模拟鼠标事件,通常设置为true

cancelable :布尔值,表示是否可以取消,为了精确模拟鼠标事件,通常设置为true

view : 与事件关联的视图,基本都设置为document.defaultView

detail : 整数,与事件有关的详细信息,基本设置为0

screenX : 整数,事件相对屏幕的X坐标

screenY : 整数,事件相对屏幕的Y坐标

clientX : 整数,事件相对视口的X坐标

clientY : 整数,事件相对视口的Y坐标

ctrlKey : 布尔值,表示是否按下Ctrl键,默认false

altKey : 布尔值,表示是否按下Alt键,默认false

shiftKey : 布尔值,表示是否按下Shift键,默认false

metaKey : 布尔值,表示是否按下Meta键,默认false

button : 整数,表示按下哪个鼠标键,默认0

relatedTarget : 对象,表示与事件相关的对象,只在mouseovermouseout时使用

案例:

var btn = document.getElementById("btn");
var myEvent = document.createEvent("MouseEvents");
myEvent.initMouseEvent(
    "click", true, true, document.defaultView, 
    0, 0, 0, 0, 0,
    false, false, false, false, 0, null
)
btn.dispatchEvent(myEvent);
6.1.2 模拟键盘事件

DOM3级规定,使用createEvent()方法传入KeyboardEvent创建一个键盘事件,返回的对象有一个initKeyEvent()方法,有8个参数:

type : 字符串,表示触发的事件类型,如keydown

bubble : 布尔值,表示是否冒泡,为了精确模拟键盘事件,通常设置为true

cancelable :布尔值,表示是否可以取消,为了精确模拟键盘事件,通常设置为true

view : 与事件关联的视图,基本都设置为document.defaultView

key : 整数,表示按下的键的键码

localtion : 整数,表示按下哪里的键,默认0表示主键盘,1表示左,2表示右,3表示数字键盘,4表示移动设备(即虚拟键盘),5表示手柄

modifiers : 字符串,空格分隔的修改件列表,如"shift"

repeat : 整数,在一行中按了多少次这个键

由于DOM3级不提倡使用keypress事件,因此只能用这个方式来模拟keyup/keydown事件。

模拟按住Shift和A键的案例:

var btn = document.getElementById("btn");
var myEvent;

// 以DOM3级方式创建
if(document.implementation.hasFeature("KeyboardEvents", "3.0")){
    myEvent = document.createEvent("KeyboardEvent");
    myEvent.initKeyboardEvent(
        "keydown", true, true, document.defaultView,
        "a", 0, "Shift", 0
    );
}
btn.dispatchEvent(myEvent);
6.1.3 模拟其他事件

如模拟变动事件HTML事件

模拟变动事件

通过createEvent()传入MutationEvents参数创建,返回一个initMutationEvent()方法,这个方法接收参数包括:type/bubbles/cancelable/relatedNode/preValue/newValue/attrName/attrChange,下面模拟一个案例:

var btn = document.getElementById("btn");
var myEvent = document.createEvent("MutationEvents");
myEvent.initMutationEvent(
    "DOMNodeInserted", true, false, someNode, "", "", "", 0
);
btn.dispatchEvent(myEvent);

模拟HTML事件

通过createEvent()传入HTMLEvents参数创建,返回一个initEvent()方法,下面模拟一个案例:

var btn = document.getElementById("btn");
var myEvent = document.createEvent("HTMLEvents");
myEvent.initEvent("focus", true, false);
btn.dispatchEvent(myEvent);
6.1.4 自定义DOM事件

通过createEvent()传入CustomEvent参数创建,返回一个initCustomEvent()方法,有4个参数:

type : 字符串,表示触发的事件类型,如keydown

bubble : 布尔值,表示是否冒泡,为了精确模拟键盘事件,通常设置为true

cancelable :布尔值,表示是否可以取消,为了精确模拟键盘事件,通常设置为true

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

案例:

var btn = document.getElementById("btn");
var myEvent;

// my_event在前面定义 2.6 跨浏览器事件处理程序
my_event.addMyEvent(btn, "myevent", function(event){
    alert("btn detail ", event.detail);
});

my_event.addMyEvent(document, "myevent", function(event){
    alert("document detail ", event.detail);
});


// 以DOM3级方式穿件
if(document.implementation.hasFeature("CustomEvents", "3.0")){
    myEvent = document.createEvent("CustomEvent");
    myEvent.initCustomEvent(
        "myevent", true, false, "hello leo",
    );
    btn.dispatchEvent(myEvent);
}
6.2 IE中的事件模拟

IE8及之前的版本模拟事件和DOM中模拟思路相似:想创建event对象再指定信息,最后触发。
区别在于,IE中使用document.createEventObject()方法创建event对象,并且不接收参数,返回一个通用event对象,我们要做的就是给这个event对象添加信息,最后在目标上调用fireEvent()方法,并接受两个参数(事件处理程序的名称和event对象)。
在调用fireEvent()方法会自动添加srcElementtype属性,我们需要手动添加其他属性,下面模拟一个click事件:

var btn = document.getElementById("btn");
var myEvent = document.createEventObject();

myEvent.screenX = 100;
myEvent.screenY = 0;
myEvent.clientX = 100;
myEvent.clientY = 0;
myEvent.ctrlKey = false;
myEvent.altKey = false;
myEvent.shiftKey = false;
myEvent.button = 0;

btn.fireEvent("onclick", event);
参考文章

《JavaScript高级程序设计》第13章 事件

本部分内容到这结束

Author 王平安
E-mail pingan8787@qq.com
博 客 www.pingan8787.com
微 信 pingan8787
每日文章推荐 https://github.com/pingan8787...
JS小册 js.pingan8787.com

欢迎关注微信公众号【前端自习课】每天早晨,与您一起学习一篇优秀的前端技术博文 .

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108871.html

相关文章

  • 重温基础】21.高阶函数

    摘要:欢迎您的支持系列目录复习资料资料整理个人整理重温基础篇重温基础对象介绍重温基础对象介绍重温基础介绍重温基础相等性判断重温基础闭包重温基础事件本章节复习的是中的高阶函数,可以提高我们的开发效率。 本文是 重温基础 系列文章的第二十一篇。 今日感受:想家。 本人自己整理的【Cute-JavaScript】资料,包含:【ES6/ES7/ES8/ES9】,【JavaScript基础...

    wua_wua2012 评论0 收藏0
  • 重温基础】22.内存管理

    摘要:内存泄露内存泄露概念在计算机科学中,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。判断内存泄漏,以字段为准。 本文是 重温基础 系列文章的第二十二篇。 今日感受:优化学习方法。 系列目录: 【复习资料】ES6/ES7/ES8/ES9资料整理(个人整理) 【重温基础】1-14篇 【重温基础】15.JS对象介绍 【重温基础】16.JSON对象介绍 【重温基础】1...

    Pandaaa 评论0 收藏0
  • 重温基础】7.时间对象

    摘要:本文是重温基础系列文章的第七篇。系列目录复习资料资料整理个人整理重温基础语法和数据类型重温基础流程控制和错误处理重温基础循环和迭代重温基础函数重温基础表达式和运算符重温基础数字本章节复习的是中的时间对象,一些处理的方法。 本文是 重温基础 系列文章的第七篇。今日感受:做好自律。 系列目录: 【复习资料】ES6/ES7/ES8/ES9资料整理(个人整理) 【重温基础】1.语法和数据类型...

    YuboonaZhang 评论0 收藏0
  • 重温基础】17.WebAPI介绍

    摘要:本文是重温基础系列文章的第十七篇。系列目录复习资料资料整理个人整理重温基础篇重温基础对象介绍重温基础对象介绍本章节复习的是中的关于相关知识,介绍的比较多。表示在给定的时间的相关设备的位置。所有现代浏览器均支持对象和使用。 本文是 重温基础 系列文章的第十七篇。今日感受:挑战。 系列目录: 【复习资料】ES6/ES7/ES8/ES9资料整理(个人整理) 【重温基础】1-14篇 【...

    android_c 评论0 收藏0
  • 重温基础】14.元编程

    摘要:本文是重温基础系列文章的第十四篇。元,是指程序本身。有理解不到位,还请指点,具体详细的介绍,可以查看维基百科元编程。拦截,返回一个布尔值。 本文是 重温基础 系列文章的第十四篇。 这是第一个基础系列的最后一篇,后面会开始复习一些中级的知识了,欢迎持续关注呀! 接下来会统一整理到我的【Cute-JavaScript】的JavaScript基础系列中。 今日感受:独乐乐不如众乐乐...

    cc17 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<