zoukankan      html  css  js  c++  java
  • JavaScript中的事件

    1、DOM事件流概念

    DOM模型是一个树形结构,在DOM模型中,HTML元素是有层次的。当一个HTML元素上产生一个事件时,该事件会在DOM树中元素节点与根节点之间按特定的顺序传播,路径所经过的节点都会收到该事件,这个传播过程就是DOM事件流。

    DOM事件标准定义了两种事件流,分别是捕获事件流冒泡事件流

    一般来说,只有同类事件才会被子元素冒泡或者捕获触发。但触发 click 事件时,因为在一个元素上只有相继触发 mousedown 和 mouseup 事件后,才会触发 click 事件,如果 mousedown 或 mouseup 中的任何一个被取消,都不会触发 click 事件。所以其实触发一个元素的 click 事件,实际上也触发了该元素的 mousedown 和 mouseup 事件,所以它的父元素的 click、mousedown、mouseup事件也可能会被冒泡或者捕获流触发。

    1.1、冒泡事件流

    默认情况下(使用onclick或者addEventListener来给元素绑定事件,默认情况下绑定的就是该节点在冒泡事件流中触发的事件),事件使用冒泡事件流。当事件(例如单击事件)在某一DOM元素上被触发时,事件将沿着该节点的各个父结点冒泡穿过整个DOM节点层次。在冒泡过程中的任何时候都可以终止事件的冒泡。如果不停止事件的传播,事件将一直通过DOM冒泡直至到达文档根。

    冒泡事件流点击哪个节点就从哪个节点开始冒泡。当触发子元素的事件时,父元素的同类事件也会跟着后面触发。比如下面示例代码:

    <div id="outer">
       <div id="middle">
            <div id="inner">
                click me!
            </div>
        </div>
    </div>
    <script>
           var innerCircle= document.getElementById("inner");
            innerCircle.onclick= function () {
                alert("innerCircle");
            };
            var middleCircle= document.getElementById("middle");
            middleCircle.onclick=function(){
                alert("middleCircle");
            }
            var outerCircle= document.getElementById("outer");
            outerCircle.onclick= function () {
                alert("outerCircle");
            }
    </script>

    如上图所示:有三层节点,每个节点都使用 onclick 方式来关联点击事件(该方式关联事件默认该节点是在冒泡事件流中触发事件):

    当点击最里面的绿色节点时,触发事件顺序:绿色节点的事件 -> 蓝色节点事件 -> 粉色节点事件

    当点击中间的蓝色节点时,触发事件顺序:蓝色节点事件 -> 粉色节点事件(注意:此时并没有触发最里面的绿色节点的事件,因为此时它根本就不在冒泡事件流内)

    1.2、捕获事件流

    与冒泡模型相反,在捕获事件流模型中,事件的处理将从DOM层次的根开始,而不是从触发事件的目标元素开始,事件被从目标元素的所有所有祖先元素依次往下传递。在这个过程中,事件会被从文档的根到事件目标元素之间各个继承派生的元素所捕获。

     

    当使用 addEventListener 方式来定义事件,并把第三个参数设为 true 时,此时节点绑定的事件是在捕获事件流中触发的。事件触发顺序是先触发最外面的绑定同类事件的根节点,然后逐层深入,直到目标节点的事件。

    3、DOM标准的事件模型

    DOM标准同时支持捕获事件模型和冒泡事件模型,但是,捕获事件模型先发生。两种事件流都会触发DOM中的所有对象,从document对象开始,也在document对象结束。

     

    示例代码:

     <div id="outer">
        <div id="middle">
          <div id="inner">
            click me!
          </div>
        </div>
      </div>
      <script>
        var innerCircle = document.getElementById("inner");
        innerCircle.addEventListener("click", function () {
          alert("innerCircle的click事件在捕获阶段被触发");
        }, true);
        innerCircle.addEventListener("click", function () {
          alert("innerCircle的click事件在冒泡阶段被触发");
        }, false);
    
        var middleCircle = document.getElementById("middle");
        middleCircle.addEventListener("click", function () {
          alert("middleCircle的click事件在捕获阶段被触发");
        }, true);
        middleCircle.addEventListener("click", function () {
          alert("middleCircle的click事件在冒泡阶段被触发");
        }, false);
        
        var outerCircle = document.getElementById("outer");
        outerCircle.addEventListener("click", function () {
          alert("outerCircle的click事件在捕获阶段被触发");
        }, true);
        outerCircle.addEventListener("click", function () {
          alert("outerCircle的click事件在冒泡阶段被触发");
        }, false);
      </script>

    三个节点同时定义了捕获事件和冒泡事件,当事件触发时,先触发捕获事件然后触发冒泡事件。比如:

    点击绿色节点:粉色节点捕获事件 -> 蓝色节点捕获事件 -> 绿色节点捕获事件 -> 绿色节点冒泡事件 -> 蓝色节点冒泡事件  -> 粉色节点冒泡事件

    点击蓝色节点:粉色节点捕获事件 -> 蓝色节点捕获事件 -> 蓝色节点冒泡事件  -> 粉色节点冒泡事件

    以此类推。。。

    4、不同绑定事件方式

    4.1、onclick事件(冒泡阶段触发)

    使用onclick 定义事件只能给节点绑定一个回调函数,绑定多个回调函数时后面的会覆盖前面定义的事件。而 addEventListener 可以给节点绑定多个回调函数

    4.2、addEventListener 定义事件(默认冒泡阶段触发)

    addEventListener() 方法可以传递三个参数:

    element.addEventListener(event, function, boolean)  

    第三个参数是可选的,用来指定事件是在捕获或冒泡阶段执行:false(默认值):事件句柄在冒泡阶段执行;true:事件句柄在捕获阶段执行

    使用 addEventListener() 方法绑定事件可以给元素绑定多个事件,后面添加的事件不会覆盖已存在的事件。

    4.3、jQuery的on、bind绑定事件(冒泡阶段)

    用 jQuery 的 on() 和 bind() 方法来绑定事件,该事件可以被子元素的相同事件在冒泡阶段触发,但捕获阶段不会触发。

    使用 JQ 绑定事件也同样会默认给函数传 event 参数,也可以用 event.stopPropagation() 方法来阻止事件冒泡和捕获。

    $('#inner').bind('click', function (e) {
        console.log('里');
        e.stopPropagation();
    })

    jquery 中的 on() 、bind() 方法可以在被选元素及子元素上一次性添加一个或多个事件处理程序,并且它跟之前绑定的事件不会冲突,并不会覆盖掉之间通过 JS 或者 JQ 绑定的事件,跟 addEventListener 绑定事件一样。

    $().bind("click mouseout",function(){...});   //多个事件可以用空格隔开
    //上面的事件并不会覆盖掉下面的事件
    divDom.onclick = function () {
        console.log("里 -- js");
    };
    
    //但是这个事件会覆盖掉上面通过js绑定的事件
    divDom.onclick = function () {
        console.log("里 -- js2");
    };

    5、阻止冒泡和捕获(event.stopPropagation())

    event.stopPropagation() 方法可以阻止冒泡和捕获。在ie中,event是全局的可以通过window.event来获取,在其他浏览器中都是作为事件函数的默认参数传入的。
    //在onclick中
    innerCircle.onclick = function (event) {
          alert("innerCircle");
          var e = event || window.event;  //兼容IE,在IE8之前要用window.event
          e.stopPropagation();
    };
    
    //不写event参数时的写法
    //不写event参数时,切勿写成event=event||window.event;在某些浏览器上可能会有点问题
    innerCircle.onclick = function () { alert("innerCircle"); var e = arguments.callee.caller.arguments[0] || window.event; //第一项表示的是函数的第一个参数,即使给函数传了参数时也会拿到点击事件的event值。不建议写arguments[0],这样如果给函数传了参数就会拿到函数传入的第一个参数,不一定是event e.stopPropagation(); }; //在addEventListener中 middleCircle.addEventListener("click", function () { alert("middleCircle的click事件在捕获阶段被触发"); event.stopPropagation(); }, true);

    节点绑定的事件回调函数执行该方法后,事件就只运行到这里,不管此时是在冒泡还是捕获阶段,后面由冒泡或者捕获事件流触发的事件都不会触发。

    6、阻止事件的默认行为(preventDefault)

    有些元素本身在浏览器中有默认行为,比如:链接<a>,提交按钮<input type=”submit”>等,链接<a>的默认动作就是跳转到指定页面。有时候我们会想要取消元素的默认行为。当然如果元素本身就没有默认行为,那就没必要去调用取消默认行为的方法。

    //假定有链接<a href="http://www.baidu.com/" id="baidu">百度</a>
    var a = document.getElementById("baidu");
    a.onclick =function(e){
      if(e.preventDefault){     //判断浏览器是否非IE浏览器 
        e.preventDefault();    //非IE浏览器下使用preventDefault方法
      }else{
        window.event.returnValue == false;     ////IE浏览器下令事件(window.event)的returnValue属性为false;
      }
    }

     

    7、addEventListener的passive选项

    addEventListener 的 passive 选项用在移动端能大大提高性能。比如很多移动端的页面都会监听 touchstart 等 touch 事件,或者滚动onScroll事件,让这些事件发生时触发一些函数。比如:

    document.addEventListener("touchstart", function(e){
        ... // 但是浏览器并不知道这里会不会有 e.preventDefault() 来阻止默认行为
    })

    由于 touchstart 事件对象的 cancelable 属性为 true,也就是说它的默认行为可以被通过 preventDefault() 方法阻止,那它的默认行为是什么呢,通常来说就是滚动当前页面(还可能是缩放页面),如果它的默认行为被阻止了,浏览器就必须保持页面静止不动。但浏览器根本无法预先知道一个监听器会不会调用 preventDefault(),它能做的只有等监听器执行完后再去执行默认行为(也就是说浏览器必须等到回调函数执行完然后再去滚动页面),而监听器执行是要耗时的,有些甚至耗时很明显,这样就会导致页面卡顿。即便监听器是个空函数,也会产生一定的卡顿,毕竟空函数的执行也会耗时。

    但绝大部分的监听器不会阻止浏览器的默认行为,浏览器相当于是在白等。所以,passive 选项诞生了,passive 表示监听器不会对事件的默认行为说 no,浏览器知道了一个监听器是 passive 的,它就可以在两个线程里同时执行监听器中的 JavaScript 代码和浏览器的默认行为了(也就是可以一边滚动一边执行回调函数里的JS代码了,这样就不会卡顿了),把 passive 选项设为 true 即可告知浏览器该JS代码不会阻止默认行为。

    参考:https://blog.csdn.net/hhlljj0828/article/details/79497734?utm_source=blogxgwz5

    8、关于鼠标的事件

    onclick:鼠标点击事件,多用在某个对象控制的范围内的鼠标点击
    ondblClick:鼠标双击事件
    onmouseDown:鼠标上的按钮被按下了
    onmouseUp:鼠标按下后,松开时激发的事件
    onmouseOver:当鼠标移动到某对象范围的上方时触发的事件
    onmouseMove:鼠标移动时触发的事件
    onmouseOut:当鼠标离开某对象范围时触发的事件
    onkeyPress:当键盘上的某个键被按下并且释放时触发的事件.[注意:页面内必须有被聚焦的对象]
    onkeyDown:当键盘上某个按键被按下时触发的事件[注意:页面内必须有被聚焦的对象]
    onkeyUp:当键盘上某个按键被按放开时触发的事件[注意:页面内必须有被聚焦的对象]

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    多线程2
    多线程1
    Mybatis动态代理开发
    Mybatis的mapper.xml文件也是要加文件头的
    ssm框架只使用mybatis配置sqlmapconfig.xml
    ssm整合之web.xml配置
    SpringMVC三大组件的配置
    spring开启注解配置
    如何开发 Sublime Text 2 的插件
    ASP.NET MVC 5改进了基于过滤器的身份验证
  • 原文地址:https://www.cnblogs.com/wenxuehai/p/10443807.html
Copyright © 2011-2022 走看看