DOM的默认事件、事件模型、事件委托、阻止默认事件、冒泡事件的方式等。

原生JavaScript事件详解:
http://www.cnblogs.com/iyangyuan/p/4190773.html

DOM0,DOM2,DOM3事件,事件基础知识入门

DOM0,DOM2,DOM3事件,事件基础知识入门:http://www.cnblogs.com/diligenceday/p/4175721.html
[解惑]JavaScript事件机制:
http://www.cnblogs.com/hustskyking/p/problem-javascript-event.html

  事件是javascript和HTML交互基础, 任何文档或者浏览器窗口发生的交互, 都要通过绑定事件进行交互;
  事件有DOM0, DOM2和DOM3的区分(别问我怎么少了一个DOM1, 也没找到DOM1的信息啊,);

  DOM0就是直接通过 onclick写在html里面的事件, 比如:

<input onclick="alert(1)" />

  DOM2是通过addEventListener绑定的事件, 还有IE下的DOM2事件通过attachEvent绑定;
  DOM3是一些新的事件, 区别DOM3和DOM2的方法我感觉是DOM3事件有分大小写的,DOM2没有;

  事件流
  事件流
  
  IE的事件流是冒泡, 从里面往上面冒, netscape是从外部元素往内部元素捕获;
  而DOM2级的事件规定了事件流包含三个阶段包括: 1:事件捕获, 2:处于目标阶段, 3:事件冒泡阶段(IE8以及更早版本不支持DOM事件流);

DOM0事件

事件模型在不断发展,早期的事件模型称为DOM0级别。

DOM0事件模型,所有的浏览器都支持。直接在dom对象上注册事件名称,就是DOM0写法.

  document.getElementById("test").onclick = function(e){}; 

意思就是注册一个onclick事件。当然,它和这种写法是一个意思:

document.getElementById("test")["onmousemove"] = function(e){};

  
基于DOM0的事件,对于同一个dom节点而言,只能注册一个,后边注册的同种事件会覆盖之前注册的。接下来再说说this。事件触发时,this就是指该事件在哪个dom对象上触发。想解除事件就相当简单了,只需要再注册一次事件,把值设成null

var btn = document.getElementById("test");
        btn.onclick = function(e){
          alert("ok");
        };

原理就是最后注册的事件要覆盖之前的,最后一次注册事件设置成null,也就解除了事件绑定。

  DOM0的事件具有极好的跨浏览器优势, 会以最快的速度绑定, 如果你通过DOM2绑定要等到JS运行, DOM0不用, 因为DOM0是写在元素上面的;

DOM2事件

DOM2支持同一dom元素注册多个同种事件。
DOM2新增了捕获和冒泡的概念。
DOM2事件通过addEventListener和removeEventListener管理,当然,这是标准。

注册事件时,通常使用捕获或冒泡的。事件只会因为捕获或者冒泡触发一次.
addEventListener当然就是注册事件,她有三个参数,分别为:”事件名称”, “事件回调”, “捕获/冒泡”

    obj.addEventListener("click", func, true); // 捕获方式
    obj.addEventListener("click", func, false); // 冒泡方式

DOM2事件的冒泡和捕获
事件名称就不用多说了,相比DOM0,去掉了前边的on而已。
事件回调也很好理解,事件触发了总得通知你吧!回调时和DOM0一样,也会默认传入一个event参数,同时this是指触发该事件的dom节点。
最后一个参数是布尔型,true代表捕获事件,false代表冒泡事件。

   <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <title></title>
            <meta charset="utf-8" />
            <style type="text/css">
                #p { width: 300px; height: 300px; padding: 10px;  border: 1px solid black; }
                #c { width: 100px; height: 100px; border: 1px solid red; }
            </style>
        </head>
        <body>
        <div id="p">
            parent
            <div id="c">
                child
            </div>
        </div>
        <script type="text/javascript">
            var p = document.getElementById('p'),
                    c = document.getElementById('c');
            c.addEventListener('click', function () {
                alert('子节点捕获')
            }, true);

            c.addEventListener('click', function (e) {
                alert('子节点冒泡')
            }, false);

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

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

  这个依次会打出父节点捕获,子节点捕获,子节点冒泡和父节点冒泡,(注意:如果你在目标元素上改变绑定事件的顺序, 这些事件可能就不按照捕获和冒泡的顺序来了,而是根据捕获和冒泡的顺序进行触发 , 这个有解决方法,参考:) ==>>(叶小钗的东东)http://www.cnblogs.com/yexiaochai/p/3567597.html );

  捕获的事件是按照顺序执行的, 而冒泡的事件在有的浏览器中的按照顺序执行有的按照相反的顺序执行;
  说实话啊,事件捕获没啥用处;

  还有一点要注意的是:元素点击里面的this有问题哦, 在IE8和和IE8以前, 通过attachEvent绑定的事件里面的this是window;

        <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <title></title>
            <meta charset="utf-8" />
            <style type="text/css">
                #p { width: 300px; height: 300px; padding: 10px;  border: 1px solid black; }
            </style>
        </head>
        <body>
        <div id="p">
            p
        </div>
        <script type="text/javascript">
            var p = document.getElementById('p');
            p.attachEvent("onclick",function(){
                alert(this);
            })
            //在IE5678这个弹出的是window哦,这个要主要, 要让this 指向这个元素通过apply或者call改变上下文
        </script>
        </body>
        </html>

  chrome下有个getEventListeners可以获取元素绑定事件, 从小钗哪里抄的,代码如下:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title></title>
</head>
<body>
<div id="d">ddssdsd</div>
  <script type="text/javascript">
    var node = document.getElementsByTagName('*');
    var d = document.getElementById('d');
    d.addEventListener('click', function () {
      alert();
    }, false);
    d.addEventListener('click', function () {
      alert('我是第二次');
    }, false);
    d.onclick = function () {
      alert('不规范的绑定');
    }
    d.addEventListener('click', function () {
      alert();
    }, true);

    d.addEventListener('mousedown', function () {
      console.log('mousedown');
    }, true);
    var evets = typeof getEventListeners == 'function' && getEventListeners(d);
    getEventListeners(d)
  </script>
</body>
</html>

——-这里我试了下报错:index_3.html:87 Uncaught ReferenceError: getEventListeners is not defined———chrome下——–直接调试中可用:
Chrome DevTools->console->getEventListeners(d);

  这个兼容问题常见的解决方法,一般来说够用了:

    <script>
     var eventUtil = {
        add : function(el, type, handler) {
            if(el.addEventListener) {
                el.addEventListener(type, handler, false);
            }else if( el.attachEvent ) {
                el.attachEvent("on"+type, handler);
            }else{
                el["on"+type] = handler;
            }
        },
        off : function(el, type, handler) {
            if( el.removeEventListener ) {
                el.removeEventListener(type, handler, false)
            }else if( el.detachEvent ) {
                el.detachEvent(type, handler);
            }else{
                el["on"+type] = null;
            }
        }
     };
    </script>

其实,事件触发时,会默认传入一个event对象,前边提过了,这个event对象上有一个方法:stopPropagation,通过此方法,可以阻止冒泡,这样外层div就接收不到事件了。代码如下:

var btn = document.getElementById("test");
var btnInner = document.getElementById("testInner");

btn.addEventListener("click", function(e){
  alert("ok1");
}, false);

btnInner.addEventListener("click", function(e){
  //阻止冒泡
e.stopPropagation();
  alert("ok");
}, false);

终于要说说怎么解除事件了。解除事件语法:btn.removeEventListener(“事件名称”, “事件回调”, “捕获/冒泡”);
这和绑定事件的参数一样,详细说明下:

      ·  事件名称,就是说解除哪个事件呗。
      ·  事件回调,是一个函数,这个函数必须和注册事件的函数是同一个。
      ·  事件类型,布尔值,这个必须和注册事件时的类型一致。

也就是说,名称、回调、类型,三者共同决定解除哪个事件,缺一不可。

事件对象

  无论在DOM0还是DOM2还是DOM3中都会在事件函数中传入事件对象;

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <meta charset="utf-8" />
        <style type="text/css">
            #p { width: 300px; height: 300px; padding: 10px;  border: 1px solid black; }
        </style>
    </head>
    <body>
    <div id="p">
        p
    </div>
    <script type="text/javascript">
        var p = document.getElementById('p');
        p.addEventListener("click",function(){
            console.log(arguments[0]);
        })
    </script>
    </body>
    </html>

  事件对象event下的属性和方法:

因为各个浏览器的事件对象不一样, 把主要的时间对象的属性和方法列出来;
bubble :    表明事件是否冒泡
cancelable :  表明是否可以取消冒泡
currentTarget : 当前时间程序正在处理的元素, 和this一样的;
defaultPrevented: false ,如果调用了preventDefualt这个就为真了;
detail: 与事件有关的信息(滚动事件等等)
eventPhase: 如果值为1表示处于捕获阶段, 值为2表示处于目标阶段,值为三表示在冒泡阶段
target || srcElement: 事件的目标
trusted: 为ture是浏览器生成的,为false是开发人员创建的(DOM3)
type : 事件的类型
view : 与元素关联的window, 我们可能跨iframe;
preventDefault()    取消默认事件;
stopPropagation() 取消冒泡或者捕获;
stopImmediatePropagation() (DOM3)阻止任何事件的运行;
//stopImmediatePropagation阻止 绑定在事件触发元素的 其他同类事件的callback的运行

IE下的事件对象是在window下的,而标准应该作为一个参数, 传为函数第一个参数;
IE的事件对象定义的属性跟标准的不同,如:
cancelBubble 默认为false, 如果为true就是取消事件冒泡;
returnValue 默认是true,如果为false就取消默认事件;
srcElement, 这个指的是target, Firefox下的也是srcElement;

两个误区:

  1. 在同一个对象上注册事件,并不一定按照注册顺序执行

这一点,从上面的例子可以看出,你随便打乱四个事件绑定的顺序,结果一般不变!出现这样结果的原因是存在捕获模式和冒泡模式。之所以如此是因为事件目的地节点既绑定了冒泡事件也绑定了捕获事件,此时的执行顺序按照绑定的先后顺序执行(情况比较少见)。

  1. event.stopPropagation();就是阻止事件的冒泡

这个表述不能说他错误,但是是不完整的,他除了阻止事件的冒泡,还阻止事件的继续捕获,简而言之就是阻止事件的进一步传播。

js中的事件委托:http://www.tuicool.com/articles/jQZj6zB

事件委托:

1,什么是事件委托:通俗的讲,事件就是onclick,onmouseover,onmouseout,等就是事件,委托呢,就是让别人来做,这个事件本来是加在某些元素上的,然而你却加到别人身上来做,完成这个事件。

也就是:利用冒泡的原理,把事件加到父级上,触发执行效果。

好处呢:1,提高性能。

我们可以看一个例子:需要触发每个li来改变他们的背景颜色。

<ul id="ul">
  <li>aaaaaaaa</li>
  <li>bbbbbbbb</li>
  <li>cccccccc</li>
</ul>

window.onload = function(){
  var oUl = document.getElementById("ul");
  var aLi = oUl.getElementsByTagName("li");

  for(var i=0; i<aLi.length; i++){
    aLi[i].onmouseover = function(){
      this.style.background = "red";
    }
    aLi[i].onmouseout = function(){
      this.style.background = "";
    }
  }
}

这样我们就可以做到li上面添加鼠标事件。

但是如果说我们可能有很多个li用for循环的话就比较影响性能。

下面我们可以用事件委托的方式来实现这样的效果。html不变

window.onload = function(){
  var oUl = document.getElementById("ul");
  var aLi = oUl.getElementsByTagName("li");

/*
这里要用到事件源:event 对象,事件源,不管在哪个事件中,只要你操作的那个元素就是事件源。
ie:window.event.srcElement
标准下:event.target
nodeName:找到元素的标签名
*/
  oUl.onmouseover = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    //alert(target.innerHTML);
    if(target.nodeName.toLowerCase() == "li"){
    target.style.background = "red";
    }
  }
  oUl.onmouseout = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    //alert(target.innerHTML);
    if(target.nodeName.toLowerCase() == "li"){
    target.style.background = "";
    }
  }
}

好处2,新添加的元素还会有之前的事件。

我们还拿这个例子看,但是我们要做动态的添加li。点击button动态添加li

如:

<input type="button" id="btn" />
<ul id="ul">
  <li>aaaaaaaa</li>
  <li>bbbbbbbb</li>
  <li>cccccccc</li>
</ul>

不用事件委托我们会这样做:

window.onload = function(){
  var oUl = document.getElementById("ul");
  var aLi = oUl.getElementsByTagName("li");
  var oBtn = document.getElementById("btn");
  var iNow = 4;
  for(var i=0; i<aLi.length; i++){
    aLi[i].onmouseover = function(){
      this.style.background = "red";
    }
    aLi[i].onmouseout = function(){
      this.style.background = "";
    }
  }

  oBtn.onclick = function(){
    iNow ++;
    var oLi = document.createElement("li");
    oLi.innerHTML = 1111 *iNow;
    oUl.appendChild(oLi);
  }


}

这样做我们可以看到点击按钮新加的li上面没有鼠标移入事件来改变他们的背景颜色。

因为点击添加的时候for循环已经执行完毕。

那么我们用事件委托的方式来做。就是html不变

window.onload = function(){
  var oUl = document.getElementById("ul");
  var aLi = oUl.getElementsByTagName("li");
  var oBtn = document.getElementById("btn");
  var iNow = 4;

  oUl.onmouseover = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    //alert(target.innerHTML);
    if(target.nodeName.toLowerCase() == "li"){
    target.style.background = "red";
    }
  }
  oUl.onmouseout = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    //alert(target.innerHTML);
    if(target.nodeName.toLowerCase() == "li"){
    target.style.background = "";
    }
  }
  oBtn.onclick = function(){
    iNow ++;
    var oLi = document.createElement("li");
    oLi.innerHTML = 1111 *iNow;
    oUl.appendChild(oLi);
  }
}

阻止默认事件

http://www.2cto.com/kf/201412/359961.html
  
有一些html元素默认的行为,比如说a标签,点击后有跳转动作;form表单中的submit类型的input有一个默认提交跳转事件;reset类型的input有重置表单行为。

如果你想阻止这些浏览器默认行为,JavaScript为你提供了方法。

先上代码

 var $a = document.getElementsByTagName("a")[0];
 $a.onclick = function(e){
     alert("跳转动作被我阻止了")
     e.preventDefault();
     //return false;//也可以
 }

默认事件没有了。

既然return false 和 e.preventDefault()都是一样的效果,那它们有区别吗?当然有。

仅仅是在HTML事件属性 和 DOM0级事件处理方法中 才能通过返回 return false 的形式组织事件宿主的默认行为。

阻止冒泡事件:

function stopBubble(e){
  if(e&&e.stopPropagation){//非IE
   e.stopPropagation();
  }
  else{//IE
   window.event.cancelBubble=true;
  }
 } 
展开阅读全文

没有更多推荐了,返回首页