`

JavaScript事件

Js 
阅读更多

需要了解事件的什么?

对于事件来讲,首先,我们需要了解这样几个概念:事件;事件处理程序;事件类型;事件流;事件冒泡;事件捕获;事件对象;事件方面的性能优化(事件委托、移除事件处理程序);常见的浏览器兼容问题。
事件的概念

事件:指的是文档或者浏览器窗口中发生的一些特定交互瞬间。我们可以通过侦听器(或者处理程序)来预定事件,以便事件发生的时候执行相应的代码。
事件处理程序

事件处理程序:我们用户在页面中进行的点击这个动作,鼠标移动的动作,网页页面加载完成的动作等,都可以称之为事件名称,即:click、mousemove、load等都是事件的名称。响应某个事件的函数则称为事件处理程序,或者叫做事件侦听器。
接下来我们用一段代码来再说明一下上面这两个抽象的概念,具体解释见代码注释:

 

    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>事件-独行冰海</title>
    </head>
    <body>
        <div id="main">理解事件的基本概念</div>
    </body>
    <script>
        var main = document.getElementById('main');
        // 此处click,点击,是一种事件的名称,是浏览器窗口中发生点击的瞬间。on这个单词,其实就是让click这个事件得以相应,因此,onclick就叫做事件处理程序。下面这段代码,我们通过处理程序(onclick)为main这个元素预定了点击(click),这样在点击(click)发生的时候,执行函数中的代码(弹出一个对话框)。
        main.onclick = function(){
            alert('点击了此处哦!');
        }
    </script>
    </html>

  关于事件处理程序,从最初的发展到现在,经历了几次的变化。

事件处理程序的名字是以“on”开头,因此click事件的处理程序就是onclick。在最初,是使用HTML事件处理程序的,也就是说,某个元素(如div),支持的每一种事件,都可以使用一个与相应事件处理程序同名的HTML特性来制定(也就是标签的一个属性),这个特性的值就是能够执行的JavaScript代码。例如:

 

 

    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>事件-独行冰海</title>
    </head>
    <body>
        <p onclick="alert('click')">HTML事件处理程序</p>
    </body>
    </html>

 

 

 当然,我们也可以再onclick=””当中进行函数的调用。

但是,无论哪种方法,都暴露出来HTML事件处理程序的很多问题:

    首先,HTML代码域JavaScript代码紧密的耦合在一起,没有实现相互分离,在进行代码的更新与维护的时候就显得异常困难。
    第二,扩展事件处理程序的作用域链在不同浏览器当中会导致不同的结果。
    第三,如果不采用调用函数的方式,而是像例子中那样直接书写代码,那么代码的通用性很差,会使得整站的代码量很大,通用性差。如果提取出来,存放在函数当中,那么,会面临另一个问题——当函数还没有被定义,只是HTML、CSS代码加载完毕,用户进行点击,会完全没有反应。

 

基于上面的这些问题,人们逐渐的去完善了事件处理程序,此时出现了DOM0级事件处理程序。(第四代WEB浏览器中出现)

DOM0级事件处理程序是什么样子的呢?其实它就是我们平时最为常用的事件绑定,如下面这个例子:

 

 

    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>事件-独行冰海</title>
    </head>
    <body>
        <p id='btn'>DOM0级事件处理程序</p>
    </body>
    <script>
        var btn = document.getElementById('btn');
        btn.onclick = function(){
            alert(this.innerHTML);
        }
    </script>
    </html>

 

 

  在DOM0级事件处理程序推出之后,广为各个用户的使用,但是,却出现了这样一个问题,当我希望为同一个元素/标签绑定多个同类型事件的时候(如,为上面的这个p标签绑定3个点击事件),是不被允许的。那么,此时,出现了另一种事件处理程序,就是DOM2级的事件处理程序,在DOM2级当中,定义了两个基本方法,用于处理指定(即绑定)和删除事件处理程序的操作,分别是addEventListener()和removeEventListener(),IE9+、FireFox、Safari、Chrome和Opera都是支持DOM2级事件处理程序的。对于IE8-,则使用的是IE专有的事件处理程序:两个类似的方法——attachEvent()与detachEvent()。

具体实例代码如下:(以addEventListener为例,给出了两种书写方式)

 

 

    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>事件-独行冰海</title>
    </head>
    <body>
        <p id='btn'>DOM0级事件处理程序</p>
    </body>
    <script>
        var btn = document.getElementById('btn');
        btn.addEventListener("click", test, false);
        function test(){
            alert(this.innerHTML);
        }
    </script>
    </html>

 

    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>事件-独行冰海</title>
    </head>
    <body>
        <p id='btn'>DOM0级事件处理程序</p>
    </body>
    <script>
        var btn = document.getElementById('btn');
        btn.addEventListener("click", function(){
            alert(this.innerHTML);        
        }, false);
    </script>
    </html>

 

 

 

  addEventListener()和removeEventListener()中的第三个参数,表示的是在哪个事件阶段进行事件处理,如果是false,则指的是冒泡阶段;如果是true,则指的是捕获阶段。

在事件方面,IE与FF存在着一系列的兼容问题,具体问题可查看博文《IE浏览器与FF火狐浏览器在事件上的兼容问题》

关于如何创建一个兼容全部浏览器的事件侦听器,我们在下一篇博文《跨浏览器的事件处理函数——处理DOM2级事件兼容 》当中再做详细的介绍和代码示范。
事件类型

之前在课程的讲解当中,我们把事件分为了三大类,分别是一般事件、表单事件和页面事件。当前我们可以再做细分:

    UI事件:如load、unload、error、resize、scroll、select、DOMActive,是用户与页面上的元素交互时触发的。
    焦点事件:如blur、DOMFocusIn、DOMFocusOut、focus、focusin、focusout,在元素获得或失去焦点的时候触发,这些事件当中,最为重要的是blur和focus,有一点需要引起注意,这一类事件不会发生冒泡!
    鼠标与滚轮事件:如click、dblclick、mousedown、mouseenter、mouseleave、mousemove、mouseout、mouseover、mouseup,是当用户通过鼠标在页面执行操作时所触发的。
    滚轮事件:mousewheel(IE6+均支持)、DOMMouseScroll(FF支持的,与mousewheel效果一样)。是使用鼠标滚轮时触发的。
    文本事件:textInput,在文档中输入文本触发。
    键盘事件:keydown、keyup、keypress,当用户通过键盘在页面中执行操作时触发。
    合成事件:DOM3级新增,用于处理IME的输入序列。所谓IME,指的是输入法编辑器,可以让用户输入在物理键盘上找不到的字符。compositionstart、compositionupdate、compositionend三种事件。
    变动事件:DOMsubtreeModified、DOMNodeInserted、DOMNodeRemoved、DOMAttrModified、DOMCharacterDataModified等,当底层DOM结构发生变化时触发。IE8-不支持。
    变动名称事件:指的是当元素或者属性名变动时触发,当前已经弃用!

对于事件的基本类型,随着HTML5的出现和发展,又新增了HTML5事件、设备事件、触摸事件、手势事件等各种事件,在后面我们再详细介绍。
事件流

事件流:描述的是从页面中接收事件的顺序。

IE与原来的NetScape(网景),对于事件流提出的是完全不同的顺序。IE团队提出的是事件冒泡流;NetScape的事件流是事件捕获流。
事件冒泡

事件冒泡:表示的是,事件开始的时候由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。
事件捕获

事件捕获:表示的是,事件开始的时候由最不具体的节点接收,然后逐级向下传播到最具体的节点。
来看一个实例:

 

 

    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>事件-独行冰海</title>
    </head>
    <body>
        <div id="main">
            <p>理解事件的基本概念</p>
        </div>
    </body>
    </html>

  如果单击了p标签,那么,如果是事件冒泡流的事件流机制,则click事件将按照如下顺序进行执行:p —— div —— body —— html —— document。

如果采用捕获流的事件流机制,则click事件的执行顺序为:document —— html —— body —— div —— p
对于冒泡流的事件流机制,存在如下的兼容问题:

    <=IE5.5     p -> div -> body -> document
    >=IE6.0        p -> div -> body -> html -> document
    >=Mozilla 1.0    p -> div -> body -> html -> document -> window

欢迎大家互相学习交流。独行冰海
事件对象

事件对象:在触发DOM上的某个事件的时候,会产生一个事件对象event,而在这个对象当中会包含着所有与事件有关的信息。我们书写如下基本代码:

 

 

    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>事件-独行冰海</title>
    </head>
    <body>
        <div id="main">理解事件的基本概念</div>
    </body>
    <script>
        var main = document.getElementById('main');
        main.onclick = function(event){
            console.log(event);
        }
    </script>
    </html>

 

 

 其中有两个信息,我们最为常用,分别是type和target。

type表示的是被触发事件的类型;

target表示的是事件的目标。

其他信息,如:

    bubbles:表示事件是否冒泡
    cancelable:表示是否可以取消事件的默认行为
    currentTarget:表示事件处理程序当前正在处理事件的那个元素
    defaultPrevented:表示是否调用了preventDefault()
    detail:表示的是与事件相关的细节信息
    eventPhase:调用事件处理处理程序的阶段:1表示捕获阶段、2表示处于目标、3表示冒泡阶段

在其中还有一些其他信息,在此就不再一一列举了。
事件方面性能优化

谈一谈事件方面如何优化性能——事件委托和事件处理程序的移除

在JavaScript代码当中,添加到页面中的事件越多,页面的性能也就越差。导致这一问题的原因主要有:

    每个函数都是对象,都会占用内存。内存中对象越多,性能也就越差。
    必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。

为了进行页面的性能优化,因此我们会采用两种方法,就是上面提到的——事件委托和事件处理程序的移除。
事件委托

很多人问我,什么时候使用事件委托,其实,简单来说,当时一个页面事件处理程序比较多的时候,我们通常情况下会使用它。

事件委托主要利用了事件冒泡,只指定一个事件处理程序,就可以管理一个类型的所有事件。例如:我们为整个一个页面制定一个onclick事件处理程序,此时我们不必为页面中每个可点击的元素单独设置事件处理程序(onclick)。还是,看一个例子。
效果:点击不同的元素执行不同的操作。不使用事件委托:

 

 

    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>事件-独行冰海</title>
        <style>
            *{margin: 0;padding: 0;}
            .control span{
                float: left;
                width: 50px;
                height: 50px;
                line-height: 50px;
                font-size: 32px;
                text-align: center;
                border: 1px solid #f00;
            }
        </style>
    </head>
    <body>
        <div class='control'>
            <span id='left'>左</span>
            <span id='first'>1</span>
            <span id='second'>2</span>
            <span id='third'>3</span>
            <span id='right'>右</span>
        </div>
    </body>
    <script>
        var left = document.getElementById('left');
        var first = document.getElementById('first');
        var second = document.getElementById('second');
        var third = document.getElementById('third');
        var right = document.getElementById('right');
        left.addEventListener("click", function(){
            alert('点击的是左这个字,执行相关操作');        
        }, false);
        first.addEventListener("click", function(){
            alert('要执行第一个序号对应的相关操作');        
        }, false);
        second.addEventListener("click", function(){
            alert('要执行第二个序号对应的相关操作');        
        }, false);
        third.addEventListener("click", function(){
            alert('要执行第三个序号对应的相关操作');        
        }, false);
        right.addEventListener("click", function(){
            alert('点击的是右这个字,执行相关操作');        
        }, false);
    </script>
    </html>

 

 

 不难看出,我们使用了5个事件侦听器,每设置一个就需要绑定一个。

使用事件委托:

    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>事件-独行冰海</title>
        <style>
            *{margin: 0;padding: 0;}
            .control span{
                float: left;
                width: 50px;
                height: 50px;
                line-height: 50px;
                font-size: 32px;
                text-align: center;
                border: 1px solid #f00;
            }
        </style>
    </head>
    <body>
        <div class='control' id='control'>
            <span id='left'>左</span>
            <span id='first'>1</span>
            <span id='second'>2</span>
            <span id='third'>3</span>
            <span id='right'>右</span>
        </div>
    </body>
    <script>
        var control = document.getElementById('control');
        control.addEventListener("click", function(e){
            // 注意,此处没有考虑IE8-的浏览器,如果想书写兼容全部浏览器的事件处理程序,请查看下一篇博文
            var target = e.target;
            // 在此使用的是switch语句,也可以采用if进行判断
            switch(target.id){
                case "left" : {
                    alert('点击的是左这个字,执行相关操作');
                    break;
                }
                case "first" : {
                    alert('要执行第一个序号对应的相关操作');
                    break;
                }
                case "second" : {
                    alert('要执行第二个序号对应的相关操作');
                    break;
                }
                case "third" : {
                    alert('要执行第三个序号对应的相关操作');
                    break;
                }
                
                case "right" : {
                    alert('点击的是右这个字,执行相关操作');
                    break;
                }
            }
        }, false);
    </script>
    </html>

  简要的总结一下所谓的事件委托:给元素的父级或者祖级,甚至页面绑定事件,然后利用事件冒泡的基本原理,通过事件目标对象进行检测,然后执行相关操作。其优势在于:

    大大减少了事件处理程序的数量,在页面中设置事件处理程序的时间就更少了(DOM引用减少——也就是上面我们通过id去获取标签,所需要的查找操作以及DOM引用也就更少了)。
    document(注:上面的例子没有绑定在document上,而是绑定到了父级的div上,最为推荐的是绑定在document上)对象可以很快的访问到,而且可以在页面生命周期的任何时点上为它添加事件处理程序,并不需要等待DOMContentLoaded或者load事件。换句话说,只要可单击的元素在页面中呈现出来了,那么它就立刻具备了相应的功能。
    整个页面占用的内存空间会更少,从而提升了整体的性能。

移除事件处理程序

每当将一个事件处理程序指定给一个元素时,在运行中的浏览器代码与支持页面交互的JavaScript代码之间就会建立一个连接。连接数量也直接影响着页面的执行速度。所以,当内存中存在着过时的“空事件处理程序”的时候,就会造成Web应用程序的内存和性能问题。
那么什么时候会造成“空事件处理程序”的出现呢?

    文档中元素存在事件,通过一些DOM节点操作(removeChild、replaceChild等方法),移除了这个元素,但是DOM节点的事件没有被移除。
    innerHTML去替换页面中的某一部分,页面中原来的部分存在事件,没有移除。
    页面卸载引起的事件处理程序在内存中的滞留。

解决方法:

    合理利用事件委托;
    在执行相关操作的时候,先移除掉事件,再移除DOM节点;
    在页面卸载之前,先通过onunload事件移除掉所有事件处理程序。

 

 

 

 

 

 

分享到:
评论

相关推荐

    JavaScript事件机制详细研究

    JavaScript 事件机制详细研究 JavaScript 事件机制是指浏览器中发生的各种事件,例如点击、鼠标悬停、键盘输入等,JavaScript 通过捕捉这些事件来执行相应的操作。本文将详细介绍 JavaScript 事件机制的实现方式和...

    JavaScript 事件处理 事件绑定 示例代码

    事件绑定 示例代码JavaScript 事件处理 事件绑定 示例代码JavaScript 事件处理 事件绑定 示例代码JavaScript 事件处理 事件绑定 示例代码JavaScript 事件处理 事件绑定 示例代码JavaScript 事件处理 事件绑定 示例...

    JavaScript 事件处理 常用事件(鼠标事件、键盘事件、表单事件)示例代码

    JavaScript 事件处理 常用事件(鼠标事件、键盘事件、表单事件)示例代码JavaScript 事件处理 常用事件(鼠标事件、键盘事件、表单事件)示例代码JavaScript 事件处理 常用事件(鼠标事件、键盘事件、表单事件)示例...

    javascript事件详解

    JavaScript事件详解 JavaScript是一种基于浏览器的脚本语言,它的事件机制是实现动态交互的重要部分。在JavaScript中,事件是用户或浏览器对网页进行操作时触发的特定动作,比如点击按钮、鼠标移动等。本文将详细...

    使用webview加载本地html页面,并处理html页面中的javascript事件

    接下来,为了使WebView能够执行JavaScript代码并处理JavaScript事件,我们需要启用JavaScript支持。我们可以调用`WebSettings`类的`setJavaScriptEnabled()`方法: ```java WebSettings settings = webView....

    JavaScript 事件处理 二级菜单级联 示例代码

    JavaScript 事件处理 二级菜单级联 示例代码JavaScript 事件处理 二级菜单级联 示例代码JavaScript 事件处理 二级菜单级联 示例代码JavaScript 事件处理 二级菜单级联 示例代码JavaScript 事件处理 二级菜单级联 ...

    JavaScript 事件处理 下拉列表和可选项 示例代码

    JavaScript 事件处理 下拉列表和可选项 示例代码JavaScript 事件处理 下拉列表和可选项 示例代码JavaScript 事件处理 下拉列表和可选项 示例代码JavaScript 事件处理 下拉列表和可选项 示例代码JavaScript 事件处理 ...

    JavaScript程序设计——事件处理实验报告.docx

    实验报告详细介绍了JavaScript事件处理的相关知识,这在Web开发中是非常关键的一部分,因为事件是用户与网页交互的主要方式。以下是对各个知识点的详细说明: 1. **JavaScript事件基本概念**: - **事件**:是用户...

    javascript事件查询综合

    JavaScript事件查询是Web开发中的重要概念,它涉及到用户与网页交互时的各种响应处理。这篇文档“javascript事件查询综合”很可能是对JavaScript事件处理机制的详细阐述。在Web开发中,JavaScript事件模型允许开发者...

    JavaScript 事件的一些重要说明

    JavaScript事件是JavaScript编程中至关重要的一个概念,它用于响应用户或浏览器的行为,如点击、滚动、键盘输入等。本文将详细解析JavaScript事件的几个关键点:异步回调、事件对象、`this`关键字以及事件冒泡的管理...

    Javascript事件的定义.doc

    JavaScript事件是网页交互的核心,它定义了当特定动作发生时,浏览器如何响应。这些动作可以是用户的操作,如点击、滚动、键盘输入,或者是页面加载、数据改变等。JavaScript事件的处理方式有多种,包括事件处理属性...

    javascript事件大集合

    JavaScript事件是Web开发中不可或缺的一部分,它允许我们与用户进行交互,响应用户的操作,并以此来更新页面内容。本文将深入探讨JavaScript事件的各个方面,帮助开发者更好地理解和应用这些关键概念。 一、事件...

    关于编写性能高效的javascript事件的技术

    在前端开发中,编写高性能的JavaScript事件处理代码至关重要。高效的事件处理不仅能够提升用户体验,还能减少不必要的计算和DOM操作,从而加快页面的响应速度。随着Web应用的日益复杂,对JavaScript事件系统的优化...

    WEB页编程技巧──JavaScript事件的应用.pdf

    "WEB页编程技巧──JavaScript事件的应用.pdf" 本文档主要介绍了JavaScript事件在WEB页编程中的应用,包括JavaScript事件的概念、分类、事件处理器的使用、事件驱动编程等方面的知识点。 一、JavaScript事件概述 ...

    JAVASCRIPT事件与动态页面编程.pdf

    JAVASCRIPT事件与动态页面编程 本文概述了JAVASCRIPT事件、事件监视器和事件处理器,并通过一个示例程序详细介绍了如何使用JAVASCRIPT事件处理器进行动态页面编程。 JAVASCRIPT事件是指人机交互的结果,如鼠标移动...

    JavaScript事件和对象

    JavaScript事件和对象是JavaScript编程中不可或缺的部分,它们赋予网页动态性和交互性,使得用户与页面内容之间能够进行有效的沟通。事件驱动机制是JavaScript的核心特性之一,它允许开发者根据用户的特定行为(如...

    JavaScript事件学习小结(一)事件流

    标题中的"JavaScript事件学习小结(一)事件流"指的是JavaScript中的事件处理机制,特别是事件流的概念。事件流描述了在DOM(文档对象模型)中事件如何从根节点传播到具体的元素节点。在JavaScript中,事件是用户与...

    扣代码工具 javascript事件 捕获者2.0.zip

    "扣代码工具 JavaScript事件 捕获者2.0.zip"这个压缩包文件显然聚焦于JavaScript事件处理,特别是事件捕获的概念。事件是用户与网页交互时产生的行为,如点击按钮、滚动页面等,而事件处理则允许开发者对这些行为...

    javascript 事件

    JavaScript事件是Web开发中不可或缺的一部分,它允许用户与网页进行交互并响应用户的操作。这篇博客主要探讨了JavaScript事件的基本概念、事件模型以及如何处理事件。 首先,我们需要理解什么是JavaScript事件。...

Global site tag (gtag.js) - Google Analytics