JavaScript事件

JavaScript事件

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

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

事件处理程序:我们用户在页面中进行的点击这个动作,鼠标移动的动作,网页页面加载完成的动作等,都可以称之为事件名称,即:click、mousemove、load等都是事件的名称。响应某个事件的函数则称为事件处理程序,或者叫做事件监听器。
实例:具体解释见代码注释:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>事件</title>
</head>

<body>
    <div id="tg">
        理解事件的基本概念
    </div>
</body>
<script>

    var tg=document.getElementById('tg');//根据指定的 id 属性值得到对象
    //此处click 点击 是一种事件名称 是浏览器窗口中发生点击的瞬间 on这个单词,就是响应click这个事件 所以onclick就是事件处理程序 又叫事件侦听器 作用是为tg这个元素预定了点击 在点击发生时 执行函数中的代码
    tg.onclick=function(){
        alert('点了我');

        }
</script>
</html>

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

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

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>HTML事件</title>
</head>

<body>
     <p onclick="alert('click')">HTML事件处理程序</p>

</body>
</html>

当然,我们也可以再onclick=””当中进行函数的调用。(不建议使用这种HTML事件)

在DOM0级事件处理程序推出之后,广为各个用户的使用,但是,却出现了这样一个问题,当我希望为同一个元素/标签绑定多个同类型事件的时候(如,为上面的这个p标签绑定3个点击事件),是不被允许的。那么,此时,出现了另一种事件处理程序,就是DOM2级的事件处理程序,在DOM2级当中,定义了两个基本方法,用于处理指定(即绑定)和删除事件处理程序的操作,分别是addEventListener()和removeEventListener
具体实例代码如下:

<!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>

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



事件类型

(1)单击事件onClick

  当用户单击鼠标按钮时,产生onClick事件。同时onClick指定的事件处理程序或代码将被调用执行。通常在下列基本对象中产生:

button(按钮对象)
checkbox(复选框)或(检查列表框)
radio (单选钮)
reset buttons(重要按钮)
submit buttons(提交按钮)

在onClick等号后,可以使用自己编写的函数作为事件处理程序,也可以使用JavaScript中内部的函数。还可以直接使用JavaScript的代码等。例:

(2)onChange改变事件

  当利用text或texturea元素输入字符值改变时发该事件,同时当在select表格项中一个选项状态改变后也会引发该事件。

(3)选中事件onSelect

  当Text或Textarea对象中的文字被加亮后,引发该事件。

(4)获得焦点事件onFocus

  当用户单击Text或textarea以及select对象时,产生该事件。此时该对象成为前台对象。

(5)失去焦点onBlur

  当text对象或textarea对象以及select对象不再拥有焦点、而退到后台时,引发该文件,他与onFocas事件是一个对应的关系。

(6)载入文件onLoad

  当文档载入时,产生该事件。onLoad一个作用就是在首次载入一个文档时检测cookie的值,并用一个变量为其赋值,使它可以被源代码使用。

(7)卸载文件onUnload

  当Web页面退出时引发onUnload事件,并可更新Cookie的状态。



事件流

事件流:描述的是从页面中接收事件的顺序。
① 事件捕获阶段

② 处于目标阶段

③ 事件冒泡阶段

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

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

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

来看一个实例:

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

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

如果采用捕获流的事件流机制,则click事件的执行顺序为:document —— html —— body —— div —— p
实例:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>事件流</title>

</head>

<body>
 <div id="p">
        parent
         <div id="c">
            child
         </div>
     </div>
     <script type="text/javascript">
         var p = document.getElementById('p');
           var  c = document.getElementById('c');
       c.addEventListener('click', function () {
             alert('子节点捕获')
         }, true);

        c.addEventListener('click', function () {
             alert('子节点冒泡')
         }, false);
     p.addEventListener('click', function () {
            alert('父节点捕获')
        }, true);

        p.addEventListener('click', function () {
            alert('父节点冒泡')
        }, false);
     </script>

</body>
</html>

① 点击parent,事件首先在document上然后parent捕获到事件,处于目标阶段然后event.target也等于parent,所以触发捕获事件

由于target与currentTarget相等了,所以认为到底了,开始冒泡,执行冒泡事件

② 点击child情况有所不同,事件由document传向parent执行事件,然后传向child最后开始冒泡,所以执行顺序各位一定要清晰
事件对象

事件对象:在触发DOM上的某个事件的时候,会产生一个事件对象event,而在这个对象当中会包含着所有与事件有关的信息。

所谓事件对象,是与特定对象相关,并且包含该事件详细信息的对象。

事件对象作为参数传递给事件处理程序(IE8之前通过window.event获得),所有事件对象都有事件类型type与事件目标target(IE8之前的srcElement我们不关注了)

各个事件的事件参数不一样,比如鼠标事件就会有相关坐标,包含和创建他的特定事件有关的属性和方法,触发的事件不一样,参数也不一样(比如鼠标事件就会有坐标信息),我们这里题几个较重要的

实例1


    <!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>

bubbles

表明事件是否冒泡

cancelable

表明是否可以取消事件的默认行为

currentTarget

某事件处理程序当前正在处理的那个元素

defaultPrevented

为true表明已经调用了preventDefault(DOM3新增)

eventPhase

调用事件处理程序的阶段:1 捕获;2 处于阶段;3 冒泡阶段

这个属性的变化需要在断点中查看,不然你看到的总是0

target

事件目标(绑定事件那个dom)

trusted

true表明是系统的,false为开发人员自定义的(DOM3新增)

type

事件类型

view

与事件关联的抽象视图,发生事件的window对象

preventDefault

取消事件默认行为,cancelable是true时可以使用

stopPropagation

取消事件捕获/冒泡,bubbles为true才能使用

stopImmediatePropagation

取消事件进一步冒泡,并且组织任何事件处理程序被调用(DOM3新增)

在我们的事件处理内部,this与currentTarget相同

createEvent

可以在document对象上使用createEvent创建一个event对象

 DOM3新增以下事件:
 UIEvents
 MouseEvents
 MutationEvents,一般化dom变动
 HTMLEvents一般dom事件

使用console.log打印出的结果。
实例某段代码

var type = 'click'; //要触发的事件类型
  var bubbles = true; //事件是否可以冒泡
 var cancelable = true; //事件是否可以阻止浏览器默认事件
  var view = document.defaultView; //与事件关联的视图,该属性默认即可,不管
  var detail = 0;
  var screenX = 0;
  var screenY = 0;
  var clientX = 0;
  var clientY = 0;
 var ctrlKey = false; //是否按下ctrl
 var altKey = false; //是否按下alt
 var shiftKey = false;
 var metaKey = false;
 var button = 0;//表示按下哪一个鼠标键
 var relatedTarget = 0; //模拟mousemove或者out时候用到,与事件相关的对象

 var event = document.createEvent('MouseEvents');
 event.initMouseEvent(type, bubbles, cancelable, view, detail, screenX, screenY, clientX, clientY,
ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);

我们就自己创建了一个event对象,然后可以传给我们自己创建的事件。

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

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

target表示的是事件的目标。

其他信息,如:

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

事件模拟

事件模拟是javascript事件机制中相当有用的功能,理解事件模拟与善用事件模拟是判别一个前端的重要依据,事件一般是由用户操作触发,其实javascript也是可以触发的,比较重要的是,javascript的触发事件还会冒泡。意思就是,javascript触发的事件与浏览器本身触发其实是一样的(并不完全一致)

如此,我们这里来通过键盘事件触发刚刚的点击事件吧,我们这里点击键盘便触发child的点击,看看他的表现如何

由于是键盘触发,便不具有相关参数了,我们可以捕捉event参数,这对我们队事件传输的理解有莫大的帮助:

我们这里先创建事件参数,然后给键盘注册事件,在点击键盘时候便触发child的点击事件
实例

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
</head>

<body>
 <div id="p">
        parent
       <div id="c">
             child
         </div>
     </div>
     <script type="text/javascript">
        alert = function (msg) {
             console.log(msg);
         }

         var p = document.getElementById('p'),
         c = document.getElementById('c');
        c.addEventListener('click', function (e) {
             console.log(e);
            alert('子节点捕获')
        }, true);
         c.addEventListener('click', function (e) {
             console.log(e);
             alert('子节点冒泡')
         }, false);

         p.addEventListener('click', function (e) {
             console.log(e);
            alert('父节点捕获')
         }, true);

         p.addEventListener('click', function (e) {
             console.log(e);
            alert('父节点冒泡')
         }, false);

        document.addEventListener('keydown', function (e) {
             if (e.keyCode == '32') {
                 var type = 'click'; //要触发的事件类型
                 var bubbles = true; //事件是否可以冒泡
                 var cancelable = true; //事件是否可以阻止浏览器默认事件
                 var view = document.defaultView; //与事件关联的视图,该属性默认即可,不管
                 var detail = 0;
                 var screenX = 0;
                 var screenY = 0;
                 var clientX = 0;
                 var clientY = 0;
                 var ctrlKey = false; //是否按下ctrl
                 var altKey = false; //是否按下alt
                 var shiftKey = false;
                 var metaKey = false;
                 var button = 0; //表示按下哪一个鼠标键
                 var relatedTarget = 0; //模拟mousemove或者out时候用到,与事件相关的对象
                 var event = document.createEvent('Events');
                 event.myFlag = '汤小高';
                 event.initEvent(type, bubbles, cancelable, view, detail, screenX, screenY, clientX, clientY,
ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);
                 console.log(event);
                 c.dispatchEvent(event);
             }
         }, false);
     </script>

</body>
</html>

事件方面性能优化

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

在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事件移除掉所有事件处理程序。
时间: 2024-12-30 23:34:06

JavaScript事件的相关文章

javascript事件列表解说

javascript 事件 浏览器支持 解说 一般事件 onclick IE3.N2 鼠标点击时触发此事件 ondblclick IE4.N4 鼠标双击时触发此事件 onmousedown IE4.N4 按下鼠标时触发此事件 onmouseup IE4.N4 鼠标按下后松开鼠标时触发此事件 onmouseover IE3.N2 当鼠标移动到某对象范围的上方时触发此事件 onmousemove IE4.N4 鼠标移动时触发此事件 onmouseout IE4.N3 当鼠标离开某对象范围时触发此事件

JavaScript事件列表

javascript javascript事件列表解说 事件 浏览器支持 解说 一般事件 onclick IE3.N2 鼠标点击时触发此事件 ondblclick IE4.N4 鼠标双击时触发此事件 onmousedown IE4.N4 按下鼠标时触发此事件 onmouseup IE4.N4 鼠标按下后松开鼠标时触发此事件 onmouseover IE3.N2 当鼠标移动到某对象范围的上方时触发此事件 onmousemove IE4.N4 鼠标移动时触发此事件 onmouseout IE4.N3

传统javascript事件模型实现观察者模式

在W3C新的事件模型框架中,IE和Mozilla都实现了相应的版本,IE的是attachEvent和detachEvent来实现元素事件的添加和删除,而Mozilla则是标准的addEventListener和 removeEventListener.在传统的javascript事件模型中,我们没办法为一个页面元素注册多个事件,只有靠自己来实现观察者模式.代码来自<ajax in action>,我添加了注释 //命名空间var jsEvent = new Array(); //构造函数jsE

浅谈javascript事件取消和阻止冒泡

这篇文章主要介绍了浅谈javascript事件取消和阻止冒泡的方法和示例,有需要的小伙伴可以参考下.     取消默认操作 w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false; 在支持addEventListener()的浏览器中,也能通过调用时间对象的preventDefault()方法取消时间的默认操作.不过,在IE9之前的IE中,可以通过设置事件对象的returnValue属性为false来达到同样的效果.下面的代码假设一个事件处理程

JavaScript事件委托实例分析

  本文实例讲述了JavaScript事件委托用法.分享给大家供大家参考.具体如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var addEvent = function (elem, eventType, func) { if ( elem.addEventListener ) addEvent = function (elem, eventType, func) { elem.addEventListener(eventTy

javascript事件冒泡实例分析

  本文实例讲述了javascript事件冒泡.分享给大家供大家参考.具体分析如下: 事件冒泡: 如果元素A嵌套在元素B中,那么A被点击不仅A的onclick事件会被触发,B的onclick也会被触发, 触发的顺序是"由内而外".验证:在页面上添加一个table,table里有tr,tr里有td,td里放一个p, 在p,td,tr,table中添加事件响应 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <html xmlns="htt

浅谈JavaScript事件的属性列表

  本文向大家简单介绍了javascript事件的属性列表,非常的详细,推荐给有相同需求的小伙伴们. HTML 4.0 的新特性之一是能够使 HTML 事件触发浏览器中的行为,比如当用户点击某个 HTML 元素时启动一段 JavaScript.下面是一个属性列表,可将之插入 HTML 标签以定义事件的行为. 属性 此事件发生在何时... onabort 图像的加载被中断. onblur 元素失去焦点. onchange 域的内容被改变. onclick 当用户点击某个对象时调用的事件句柄. on

javascript 事件绑定方法与兼容ie ff解决办法

网页特效 事件绑定方法与兼容ie ff解决办法 var t = document.getelementbyid("tab1"); t.onclick = function tst(){ alert(''); } 第二种方法 var tb = document.getelementbyid("tab1"); if(window.addeventlistener){ // mozilla, netscape, firefox td_value.addeventliste

阻止JavaScript事件冒泡传递(cancelBubble 、stopPropagation)_javascript技巧

cancelBubble在IE下有效 stopPropagation在Firefox下有效 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  <html xmlns="http://www.w3.org/1999/xhtml

javascript事件冒泡详解和捕获、阻止方法_javascript技巧

一.事件的发生顺序 这个问题的起源非常简单,假设你在一个元素中又嵌套了另一个元素 复制代码 代码如下: ----------------------------------- | element1                        | |   -------------------------     | |   |element2               |     | |   -------------------------     | |