Javascript事件处理机制

刚学JS的时候就用到了事件,可是却一直没去弄懂是什么原理。各种笔面试中不乏有这问题,整理一下。

一、什么是JS的事件

 事件的定义

 惯例,事件什么?

 

...

...

...

来个严谨一点的定义:

事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。

OK,JS是事件呢。其实就是我们经常接触到的,点击按钮,鼠标悬停之类。

二、事件流

在事件流的概念上,最初两大浏览器厂商IE和Netscape的定义截然不同。

1、事件冒泡

 事件冒泡是IE定义的事件流,即事件开始由最具体的元素(例如点击事件中的点击对象)接收,然后逐级向上传播。

2、事件捕获

事件捕获却是认为最不具体的节点最早接收到事件,然后逐级向下传播。

3.DOM事件流

现在新版本的浏览器都采用了DOM事件流的概念。

包括三个阶段:

  • 事件捕获阶段
  • 处于目标阶段
  • 事件冒泡阶段

按顺序执行以上各阶段。

三、事件处理的四个方式

1、HTML事件处理程序

接在HTML代码中添加事件处理程序

<input id="btn" type="button" onclick="clickme(this)">
<script> var btn = document.getElementById("btn"); btn.value = "点我阿~~~"; var text = ["咋了", "点我干嘛", "还点", "不理你了"]; var time = 0; function clickme(e) { if (time > 3 && time < 12) { e.value = "哼"; } else if (time > 11) { e.value = "fuck"; } else { for (var i in text) { e.value = text[time]; } } time++; } </script>

2、DOM0级事件处理程序

相比第一种,DOM0级事件处理直接对于制定对象添加事件。

<input id="btn" type="button">
<script> var btn = document.getElementById("btn"); btn.value = "点我阿~~~"; var text = ["咋了", "点我干嘛", "还点", "不理你了"]; var time = 0; btn.onclick = function(){ if (time > 3 && time < 12) { this.value = "哼"; } else if (time > 11) { this.value = "fuck"; } else { for (var i in text) { this.value = text[time]; } } time++; } </script>
  • 如若要删除该事件,可直接将其值设为null

btn.onclick = null;

3、DOM2级事件处理程序

 DOM2级事件处理程序定义了两个方法,addEventListener()和removeEventListener().字面即可理解为事件的添加和删除。

<button id="btn-bind">绑定事件</button>
<script>
    function clickme() {
        alert("美丽最傻");
    }
    document.getElementById("btn-bind").addEventListener("click", clickme, false);
    document.getElementById("btn-bind").removeEventListener("click", clickme, false);
</script>

显而易见。这两个方法都带有三个参数:

  • 要处理的事件名
  • 作为事件处理程序的函数
  • 一个布尔值

解释一下这几个参数:

第一个处理的事件名同上两个处理程序相比,事件名不带on,即点击事件是'click'。

第二个参数是一个函数,这里有一个注意的地方,如果是是采用function(){...}的方式作为第二个参数传入,那是无效的。因为实际上是传入了两个完全不同的函数。

第三个参数,当布尔值为true的时候,表示在事件捕获阶段调用该处理程序,反之则表示在事件冒泡阶段调用。一般建议添加在事件冒泡阶段,为了更好的兼容浏览器。

关于事件捕获和事件冒泡等下说。

4、IE事件处理程序

IE的事件处理程序类似DOM,拥有两个方法,attchEvent()和detachEvent()

<button id="btn-bind">绑定事件</button>
<script>
    function clickme() {
        alert("美丽最傻");
    }
    document.getElementById("btn-bind").attachEvent("click",clickme);
    document.getElementById("btn-bind").detachEvent("click",clickme);
</script>

有没有发现,其实和DOM2处理程序很相像,只是少了一个参数,由于次方法是针对于IE8及其更早版本的浏览器,所以只支持事件冒泡。

现在浏览器普遍只是DOM2级事件处理,但是由于要兼顾兼容性的问题,还是需要了解这个方法。

四、事件的浏览器兼容性问题

上一节了解了四种处理程序的方法。下面就总结一下,贴一个兼容各浏览器的代码。

var EventUtil = {
        addHandler:function(element,type,handler) {
            //body
        },
        getEvent:function(event){
            return event ? event : window.event;
        },
        getTarget:function(event){
            return event.target || event.srcElement;
        },
        preventDefault:function(event){
            if(event.preventDefault){
                event.preventDefault();
            }eles{
                event.returnValue = false;
            }
        },

        removeHandler:function(element,type,handler){
            //body
        },
        stopPropagation:function(event){
            if(event.stopPropagation){
                event.stopPropagation();
            }else{
                event.cancelBubble = true;
            }
        }
    };

  

代码来自《Javascript高级程序设计》(第3版)

五、事件冒泡引发的问题

先贴一段代码

<div id="wrap">
        <div id="content">
            <div id="father">
                Father
                <div id="son">Son</div>
            </div>
        </div>
    </div>
<script>
    var father = document.getElementById("father");
    var son = document.getElementById("son");
    father.onclick = function() {
        alert("I'm father");
    }
    son.onclick = function() {
        alert("I'm son");
    }
</script>

上面的栗子中,当我点击了id为son的div之后,点击事件往上传递,这时候就会有引发一个问题,我在id为father上也加了一个点击事件,当son的冒泡事件往上传递到father的时候,同时也触发了father的点击事件,所以会分别alert出“im son”和“i'm father“

在实际应用当中也会有这种困扰,所以这时候我们需要阻止事件冒泡。

<div id="wrap">
        <div id="content">
            <div id="father">
                Father
                <div id="son">Son</div>
            </div>
        </div>
    </div>
    <script>
    function stopEventBubble(event){
        var e=event || window.event;
        if (e && e.stopPropagation){
            e.stopPropagation();    //针对除IE外浏览器
        }
        else{
            e.cancelBubble=true;  //针对IE浏览器
        }
    }
    var father = document.getElementById("father");
    var son = document.getElementById("son");
    father.onclick = function() {
        alert("I'm father");
    }
    son.onclick = function(e) {
        alert("I'm son");
        stopEventBubble(e)
    }
    </script>
原文地址:https://www.cnblogs.com/ellenwu/p/4939965.html