zoukankan      html  css  js  c++  java
  • 理解javascript中的事件模型

      javascript中有两种事件模型:DOM0,DOM2。而对于这两种的时间模型,我一直不是非常的清楚,现在通过网上查阅资料终于明白了一些。

      

      一.  DOM0级事件模型

      DOM0级事件模型是早期的事件模型,所有的浏览器都是支持的,而且其实现也是比较简单。代码如下:

    <p id = 'click'>click me</p>
    <script>
        document.getElementById('click').onclick = function(event){
            alert(event.target);
        }
    </script>

      这种事件模型就是直接在dom对象上注册事件名称,这段代码就是在p标签上注册了一个onclick事件,在这个事件函数内部输出点击的目标。而解除事件则更加简单,就是将null复制给事件函数,如下:

    document.getElementById('click'_).onclick = null;

      由此我们可以知道dom0中,一个dom对象只能注册一个同类型的函数,因为注册多个同类型的函数的话,就会发生覆盖,之前注册的函数就会无效。

    var click = document.getElementById('click');
    click.onclick = function(){
        alert('you click the first function');
    };
    click.onclick = function(){
        alert('you click the second function')
    }

      在这段代码中,我们为dom对象注册了两个onclick函数,但是结果是只执行了第二个注册的函数,前面所注册的函数被覆盖了。

      二.   DOM2级事件模型

      1.  事件捕获和事件冒泡(capture,bubble)

      首先,IE8及以下是不支持这种事件模型的。事件捕获和事件冒泡的机制如下图:

      如上图所示,123代表事件捕获,4567代表事件冒泡。首先我们使用下面的代码:

    <div id = 'outer' style = 'margin: 100px 0 0 100px;  200px;height: 200px; background: red;'>
        <div id="inner" style = 'margin-left:20px;  50px;height:50px; background: green;'></div>
    </div>

      假设我们点击了ID为inner的div,那么此时的事件流程就是,首先执行捕获阶段:document-html-body-div(outer)。然后执行冒泡阶段:div(inner)-div(outer)-body-html-document。

      2.   DOM2级的注册事件和解除事件

      在DOM2级中使用addEventListener和removeEventListener来注册和解除事件(IE8及之前版本不支持)。这种函数较之之前的方法好处是一个dom对象可以注册多个相同类型的事件,不会发生事件的覆盖,会依次的执行各个事件函数。

      addEventListener('事件名称','事件回调','捕获/冒泡')。示例如下:

    <div id = 'outer' style = 'margin: 100px 0 0 100px;  200px;height: 200px; background: red;'>
        <div id="inner" style = 'margin-left:20px;  50px;height:50px; background: green;'></div>
    </div>
    <script>
        var click = document.getElementById('inner');
        click.addEventListener('click',function(){
            alert('click one');
        },false);
        click.addEventListener('click',function(){
            alert('click two');
        },false);
    </script>

      首先我们要知道addEventListenr的第一个参数是事件名称,与DOM0级不同的是没有”on“,另外第三个参数代表捕获还是冒泡,true代表捕获事件,false代表冒泡事件。

      而在这段代码中,我们为inner的div注册了两个click事件函数,结果是浏览器会依次执行这两个函数。

      下面我们演示如何使用事件流的发生机制。

    <div id = 'outer' style = 'margin: 100px 0 0 100px;  200px;height: 200px; background: red;'>
        <div id="inner" style = 'margin-left:20px;  50px;height:50px; background: green;'></div>
    </div>
    <script>
        var click = document.getElementById('inner');
        var clickouter = document.getElementById('outer');
        click.addEventListener('click',function(){
            alert('inner show');
        },true);
        clickouter.addEventListener('click',function(){
            alert('outer show');
        },true);
    </script>

      这段代码,我们使用了捕获事件,由于inner是嵌套在outer中的,所以我们知道当使用捕获的时候outer是应该首先捕获到这个事件的,其次inner才能捕获到这个事件。那么结果就是outer首先执行,其次是inner执行。

      那么我把outer的执行时机改为冒泡的阶段呢?

    alickouter.addEventListener('click',function(){
      alert('outer show');  
    },false);

      这种情况下,就是先执行inner后执行outer了。同理我们把二者的事件执行时机都改为冒泡阶段的话,依旧是先执行inner后执行outer。那么还有个问题,就是如果我们把inner注册两个click事件,一个是在捕获阶段,另一个是在冒泡阶段,也就是说把addEventListenter的第三个参数分别设置为false和true,那么执行的顺序又是怎样的呢。

    <script>
        var click = document.getElementById('inner');
        var clickouter = document.getElementById('outer');
        click.addEventListener('click',function(){
            alert('capture show');
        },true);
        click.addEventListener('click',function(){
            alert('bubble show');
        },false);
    </script>

      这种情况下首先这些的是capture show,其次是bubble show。但是这种结果是与注册的顺序有关系的,先注册就先执行。因为我们在看事件捕获和事件冒泡示意图,发现最后具体的dom对象是只有一个的。

      那么 如果我们给outer和inner都注册了click事件但是我不希望outer执行怎么办呢?这个时候我们就需要用到stopPropagation函数了,这个函数是用来阻止冒泡,言下之意是让事件不再继续冒泡下去,这样接下来注册同样类型事件的dom对象就不会执行了。比如在自制下拉框的时候,我们点击浏览器的其他位置,我们需要下拉框的options隐藏,这时我们就要用到stopPropagation了。如下:

    <script>
        var click = document.getElementById('inner');
        var clickouter = document.getElementById('outer');
        click.addEventListener('click',function(event){
            alert('inner show');
            event.stopPropagation();
        },false);
        clickouter.addEventListener('click',function(){
            alert('outer show');
        },false);
    </script>

      正常的情况下,我们在不添加stopPropagation函数时,首先应该执行inner,然后执行outer,但是当我们在inner的事件函数中添加了stopPropagation函数之后,执行完inner的事件函数之后,就不会在执行outer的事件函数了,也可以理解为事件冒泡到inner之后就消失了,因此也就不会在执行接下来的事件函数了。

      由于事件捕获阶段没有可以阻止事件的函数,所以一般都是设置为事件冒泡。

  • 相关阅读:
    centos6.5+mono+nginx跑asp.net
    YYHS-手机信号
    NOIP2017提高组初赛
    BZOJ-4915-简单的数字题
    BZOJ-5055-膜法师(离散化+树状数组)
    YYHS-Super Big Stupid Cross(二分+扫描线+平衡树)
    BZOJ-1008-[HNOI2008]越狱(快速幂)
    BZOJ-1192-[HNOI2006]鬼谷子的钱袋
    POJ-2417-Discrete Logging(BSGS)
    BZOJ-1010-[HNOI2008]玩具装箱toy(斜率优化)
  • 原文地址:https://www.cnblogs.com/jyybeam/p/5794932.html
Copyright © 2011-2022 走看看