html中冒泡事件机制及this和event对象

所谓事件冒泡,指在一个对象(如buton)上触发某类事件(比如单击onclick事件):

1、如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,

默认情况下,处理完毕后,事件就会继续向这个对象的父级对象传播,如果父对象定义了事件处理,则父对象的事件处理会被调用,一直会传播到对象层次的最顶层,即document对象(有些浏览器是window)。

2、如果此对象上没有定义此事件的处理程序,该事件还是会沿着这个对象的父级对象向上传播,直至最顶层。

3、如果希望阻断这个传播,可以在任何一级的事件定义处理函数中进行处理,具体介绍看下面例子。

在事件处理中,会经常涉及到this和event对象,尤其涉及到冒泡事件,这时想获取到触发对象,比较复杂,我们下面来通过例子介绍。

 

下面的例子,都基于这样的dom结构例子:

    <div id="div2" style="yellow;padding: 30px;" >
        <div id="div1" style="red;" >
            <button id="btn"  >测试</button>
        </div>
    </div>

 

一、事件函数直接写在html标签中

1、冒泡例子:

    <div id="div2" style="background-color: yellow;padding: 30px;" onclick="clickDiv2">
        <div id="div1" style="background-color: red;" onclick="clickDiv1" >
            <button id="btn" onclick="clickBtn" >测试</button>
        </div>
    </div>
 
      function clickBtn(){
        console.log("clickBtn")
      }

      function clickDiv1(){
        console.log("clickDiv1")
      }

      function clickDiv2(){
        console.log("clickDiv2")
      }

如果鼠标点击 按钮,会依次输出  clickBtn-> clickDiv1->clickDiv2,这就是事件冒泡的表现。

说明:采用这种原数的方式,无法在函数最后通过返回false来阻止事件冒泡。可以用别的方式,下面继续介绍。

 

2、this对象使用

要想要在事件函数中使用this,如果在html标签中的事件注册时不传入this,则在函数中使用this,该this代表的是全局 Window对象,而不是事件所触发的对象。因此,需要显示的传入this,如下面代码:

    <div id="div2" style="background-color: yellow;padding: 30px;" onclick="clickDiv2(this)">
        <div id="div1" style="background-color: red;" onclick="clickDiv1(this)" >
            <button id="btn" onclick="clickBtn(this)" >测试</button>
        </div>
    </div>

      function clickBtn(obj){
        console.log("clickBtn:"+obj.id)
      }

      function clickDiv1(obj){
        console.log("clickDiv1:"+obj.id)
      }

      function clickDiv2(obj){
        console.log("clickDiv2:"+obj.id)
      }

 这种情况下,this始终是事件绑定的对象。比如对于clickDiv2函数,即使鼠标点击的是button,但传入的this指向的还是div2.

那么我们如果想获取事件源,即最早触发事件的对象,比如在 clickDiv2函数中判断鼠标点击的是哪个对象,该怎么做呢?

这时就要用到event对象了。

 

3、event对象使用

 event对象是个全局对象,即可以直接在函数中使用,不需要参数传入,也可以参数传入,如下面例子:

    <div id="div2" style="background-color: yellow;padding: 30px;" onclick="clickDiv2(event)">
        <div id="div1" style="background-color: red;" onclick="clickDiv1(event)" >
            <button id="btn" onclick="clickBtn(event)" >测试</button>
        </div>
    </div>

      function clickBtn(ev){
        console.log("clickBtn:"+ev.currentTarget.id)
        console.log("clickBtn:"+ev.target.id)
      }

      function clickDiv1(ev){
        console.log("clickDiv1:"+ev.currentTarget.id)
        console.log("clickDiv1:"+ev.target.id)
      }

      function clickDiv2(ev){
        console.log("clickDiv2:"+ev.currentTarget.id)
        console.log("clickDiv2:"+ev.target.id)
      }

运行上面代码,我们会发现 event对象的currentTarget属性指向绑定事件的对象,等同于this对象。

target属性指向最初触发的对象。

比如我们鼠标点击button按钮,这时在clickDiv2中通过 ev.target 获取的是 button对象;通过ev.currentTarget获取的是div2对象。

 

4、阻止冒泡事件

如果我们希望点击button按钮,不会触发 div1,div2的click事件。可以用到event对象的方法。

event对象有两个容易混淆的方法:

一个是 preventDefault 方法,作用是取消一个目标元素的默认行为(如提交form表单),注意该方法不能阻止事件冒泡。

另一个是stopPropagation方法,该方法是阻止事件冒泡。

需要说明的是,在事件处理函数中,如果return false,则会阻止默认行文,但不会阻止事件冒泡。

下面代码会阻止事件冒泡:

  function clickBtn(ev){
        console.log("clickBtn:"+ev.currentTarget.id)
        console.log("clickBtn:"+ev.target.id)
        ev.stopPropagation()
      }

在clickBtn函数中添加ev.stopPropagation()语句后,当点击Button时,button的事件函数会被调用,但因为阻止了事件冒泡,div1,div2的事件处理函数不会被调用。

 

说明:对于原数的Js事件,除了直接在html标签中的定义外,还可以通过代码动态定义,如:

      var a = document.getElementById("btn");
      a.onclick =function(ev){
        console.log("clickBtn:"+ev.currentTarget.id)
        console.log("clickBtn:"+ev.target.id)
        ev.stopPropagation()
      }

如果要移除html元素中定义的事件,??

 

5、事件响应函数为对象的方法

我们看下,如果事件响应的函数为对象的方法,会出现什么变化。

<button onclick="handleDemo.clickBtn(this)">测试</button>

代码如下

<script>
    function HandleDemo(){
        this.msg="good";
    }
    HandleDemo.prototype.clickBtn=function(obj){
        alert(obj.innerHTML);
        alert(this.msg);
    }
    var handleDemo = new HandleDemo();
</script>

这时会发现 clickBtn 方法中的 this 指向的是 handleDemo 对象。 参数obj因为是传入的,指向的是button对象,这个没变。

说明:直接在html标签中绑定事件,是一件非常不好的编码习惯,强烈不建议推荐。下面我们介绍用jquery进行事件处理。

 

二、利用jquery绑定事件

1、方式一:

<button id="btn">测试</button>

脚本代码

<script>
    $("#btn").click(clickBtn);
    function clickBtn(event){
        alert(this.innerHTML);
        alert(event.currentTarget.innerHTML);
    }
</script>

上面代码 通过调用jquery对象的 click方法,参数就是事件响应处理函数。
这个函数可以带一个参数,jquery会把事件对象event传入。参数名可以是任意的,不一定叫event。

如果不定义参数,在函数中也可直接使用event。但一般如果需要用到event对象,最好显式定义下。

这时我们会发现,在函数体中直接使用的this指向的是 button对象。 我们可以不显示的定义对象,采用匿名函数的方式,如:

<script>
    $("#btn").click(function(ev){
        alert(this.innerHTML);
        alert(ev.currentTarget.innerHTML);
    });
</script>

这个代码与上面代码的效果完全一样。

我们再来看下,如果传给click方法的是对象的方法呢?

<script>
    function HandleDemo(){
        this.msg="good";
    }
    HandleDemo.prototype.clickBtn=function(ev){
        alert(this.innerHTML);
        alert(ev.currentTarget.innerHTML);
    }
    var handleDemo = new HandleDemo();
    
    $("#btn").click(handleDemo.clickBtn);
</script>


这时,我们发现clickBtn中的 this指向的依然是 button对象,并不是我们想象中的 handleDemo对象。

这样就带来一个很大的问题,因为clickBtn方法是handleDemo对象的成员,如果我们想要在clickBtn方法中访问handleDemo对象的其它成员,却没办法了。

除非直接使用全局变量,而这是很不推荐的。

下面我们介绍jquery的另外一种事件绑定方法。

 

2、方式二:bind方法

html代码依然不变

<button id="btn">测试</button>

脚本代码

<script>
    function clickBtn(ev){
        alert(this.innerHTML);
        alert(ev.currentTarget.innerHTML);
    }
    $("#btn").bind("click",clickBtn);
</script>

这时,事件处理方法依然有一个参数指向event对象。

我们发现 clickBtn中的 this 指向的是 button对象。
bind函数,有三个参数,第一个是代表事件类型;第二个是传递给事件处理的额外信息对象(会赋值给event的data属性);第三个是事件处理函数。

上面例子我们只使用了第1个和第3个。下面我们看下例子:

<script>
    function clickBtn(ev){
        alert(this.innerHTML);
        alert(ev.currentTarget.innerHTML);
        alert(ev.data.msg);
    }
    $("#btn").bind("click",{msg:"hello"},clickBtn);
</script>

采用这种方式,我们传递了额外的对象给事件处理函数。这在某些场景下还是能用到的。

下面我们看下这种方式下传入的事件处理函数是对象的方法:

<script>
    function HandleDemo(){
        this.msg="good";
    }
    HandleDemo.prototype.clickBtn=function(ev){
        alert(this.innerHTML);
        alert(ev.currentTarget.innerHTML);
        alert(ev.data.msg);
    }
    var handleDemo = new HandleDemo();

    $("#btn").bind("click",handleDemo,handleDemo.clickBtn);
</script>

我们可以将对象本身作为bind方法的第二个参数传入。以解决在方法中无法访问对象其它成员的问题。

注意:采用jquery的事件绑定,无论是用bind方法,还是上一种方法。 如果调用多次,会绑定多次,而不会后面的覆盖前面的,事件触发时,事件函数会被多次执行。

 

currentTarget
posted @ 2016-03-22 17:04  51kata  阅读(7928)  评论(0编辑  收藏  举报