zoukankan      html  css  js  c++  java
  • DOM中的事件总结

    一. 在 html 中直接绑定

      在 HTML 中绑定事件叫做内联绑定事件,HTML 的元素中有如 onclick 这样的 on*** 属性,它可以给这个 DOM 元素绑定一个类型的事件,主要是这样的:

      <div onclick="***">博客园</div>

      这里的 *** 有两种形式:

    1. 用字符串表示一段函数

      <div onclick="var a = 1; console.log(a); ">博客园</div>

    2. 用函数名表示

      <div onclick="foo(this)">博客园</div>

      这里需要添加 script 去定义函数:

      <script>
        function foo(_this) {
          console.log(_this);
          console.log(this);
        }
      </script>

      然而这内联的方式绑定时间不利于分离,所以一般我们不推荐这种做法,所以也就不再多阐述了

    二. 在 JavaScript 中绑定

    1. onclick

      来看例子:

      <div id="btn">博客园</div>

      document.getElementById('btn').onclick = function (e) {
        console.log(this.id);
        console.log(e);
      };

      观察 console.log:

      btn
      MouseEvent {isTrusted: true, screenX: 65, screenY: 87, clientX: 65, clientY: 13…}

      首先,我们获取到了 dom 元素,然后给它的 onclick 属性赋值了一个函数;点击 dom 我们发现那个函数执行了,同时发现函数中的 this 是指向当前的这个 dom 元素;细细一想,其实这和前面用的在 html 中内联绑定函数是一样的,我们同样是给 dom 的 onclick 属性赋值一个函数,然后函数中的 this 指向当前元素,只是这个过程这里我们是在 js 中做的;而还有一点区别就是前面的是赋值一段 js 字符串,这里是赋值一个函数,所以可以接受一个参数:event,这个参数是点击的事件对象。

      用赋值绑定函数的一个缺点就是它只能绑定一次:

      例如:

      document.getElementById('btn').onclick = function (e) {
        console.log(this.id);
      };
      document.getElementById('btn').onclick = function (e) {
        console.log(this.id);
      };

      可以看到这里只打印了一次 btn。

    2. addEventListener

      这个才是我们需要重点介绍的一个函数

    1.)语法:

      target.addEventListener(type, listener[, useCapture]);

      target : 表示要监听事件的目标对象,可以是一个文档上的元素 Document 本身,Window 或者 XMLHttpRequest;

      type : 表示事件类型的字符串,比如: click、change、touchstart …;

      listener : 当指定的事件类型发生时被通知到的一个对象。该参数必是实现 EventListener 接口的一个对象或函数。

      useCapture : 设置事件的捕获或者冒泡 (后文阐述) ,true: 捕获,false: 冒泡,默认为 false。

      上个例子:

      <div id="btn">博客园</div>

      var btn = document.getElementById('btn');

      btn.addEventListener(‘click’, foo1);

      function foo1(event) {
        console.log(this.id);
        console.log(event);
      }

      观察 console.log:

      btn
      MouseEvent {isTrusted: true, screenX: 37, screenY: 88, clientX: 37, clientY: 14…}

      监听函数中的 this 指向当前的 dom 元素,函数接受一个 event 参数。

    2.)绑定多个函数

      addEventListener 可以给同一个 dom 元素绑定多个函数:

      <div id="btn">博客园</div>

      var btn = document.getElementById('btn');

      btn.addEventListener('click', foo1);
      btn.addEventListener('click', foo2);

      function foo1(event) {
        console.log(666);
      }

      function foo2(event) {
        console.log(888);
      }

      可以看到 console.log:

      666
      888

      我们可以看到两个函数都执行了,并且执行顺序按照绑定的顺序执行。

      改变一下,如果我们的 useCapture 参数不同呢?
      看下面 3 组对比:

    例子:1

      var btn = document.getElementById('btn');

      btn.addEventListener('click', foo1, true);
      btn.addEventListener('click', foo2, true);

      function foo1(event) {
        console.log(666);
      }

      function foo2(event) {
        console.log(888);
      }

    例子:2

      var btn = document.getElementById('btn');

      btn.addEventListener('click', foo1, true);
      btn.addEventListener('click', foo2, false);

      function foo1(event) {
        console.log(666);
      }

      function foo2(event) {
        console.log(888);
      }

    例子:3

      var btn = document.getElementById('btn');

      btn.addEventListener('click', foo1, false);
      btn.addEventListener('click', foo2, true);

      function foo1(event) {
        console.log(666);
      }
      function foo2(event){

      console.log(888)

      }

      console.log打印出来的值并没有改变,所以执行顺序只和绑定顺序有关和 useCapture 无关。

      结论:
        我们可以给一个 dom 元素绑定多个函数,并且它的执行顺序按照绑定的顺序执行。

    3.)同一个元素绑定同一个函数

      我们给一个 dom 元素绑定同一个函数两次试试:

      <div id="btn">博客园</div>

      var btn = document.getElementById('btn');

      btn.addEventListener('btn', foo1);
      btn.addEventListener('btn', foo1);

      unction foo1(event) {
        console.log(666);
      }

      观察 console.log:

      666 

      可以看到函数只执行了一次;

    换一种方式:

      var btn = document.getElementById('btn');

      btn.addEventListener('btn', foo1, true);
      btn.addEventListener('btn', foo1, false);

      function foo1(event) {
        console.log(666);
      }

      观察 console.log:

      666
      666 

      可以看到函数执行了两次。

      结论:
        我们可以给一个 dom 元素绑定同一个函数,最多只能绑定 useCapture 类型不同的两次。

    3. attachEvent

      addEventListener 只支持到 IE 9,所以为了兼容性考虑,在兼容 IE 8 以及以下浏览器可以用 attachEvent 函数,和 addEventListener 函数表现一样。在IE浏览器中我们可以使用attachEvent.形如:object.attachEvent(event,function);这里需要注意的是event的格式都是on+事件名,如:btn事件->onclick

      例子:

      var btn = document.getElementById("btn");

      btn.attachEvent("onclick",test1);

        function test1(){

      console.log("666");

      }

    三. 事件的解绑

      与事件绑定相对应的就是事件解绑了。

    1. 通过 dom 的 on** 属性设置的事件

      对于 Bind in HTML 和 dom.onclick 绑定的事件都可以用 dom.onclick = null 来解绑事件。

    2. removeEventListener

      通过 addEventListener 绑定的事件可以使用 removeEventListener 来解绑, removeEventListener 接受的参数和 addEventListener 是一样的

      <div id="btn">博客园</div>

      var btn = document.getElementById('btn');

      btn.addEventListener('click', foo1);

      function foo1(event) {
        console.log(666);
      }
      btn.removeEventListener('click', foo1, true);

      这里发现事件并没有取消绑定,发现 removeEventListener 的 useCapture 的参数原来和绑定时候传入的不一致,我们改成 false 之后发现事件取消了。

      结论:
        对于使用 removeEventListener 函数解绑事件,需要传入的 listener useCapture 应和 addEventListener 一致才可以解绑事件。

    3. detachEvent

      通过attachEvent绑定的事件可以使用detachEvent来解绑,可接受的参数和attachEvent是一样的,如下:btn.detachEvent("on" + type, handler)

    四. DOM事件流

      DOM事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的事件捕获,为截获事件提供机会。然后是实际的目标接受事件。最后一个阶段是时间冒泡阶段,可以在这个阶段对事件做出响应。

    1. 捕获阶段(Capture Phase)

      事件的第一个阶段是捕获阶段。事件从文档的根节点流向目标对象节点。途中经过各个层次的DOM节点,并在各节点上触发捕获事件,直到到达事件的目标节点。捕获阶段的主要任务是建立传播路径,在冒泡阶段,事件会通过这个路径回溯到文档跟节点。

    2. 目标阶段(Target Phase)

      当事件到达目标节点的,事件就进入了目标阶段。事件在目标节点上被触发,然后会逆向回流,直到传播至最外层的文档节点。

    3. 冒泡阶段(Bubble Phase)

      事件在目标元素上触发后,并不在这个元素上终止。它会随着DOM树一层层向上冒泡,回溯到根节点。
    冒泡过程非常有用。它将我们从对特定元素的事件监听中释放出来,如果没有事件冒泡,我们需要监听很多不同的元素来确保捕获到想要的事件。

    4. 回到 addEventListener

      我们来做几个小对比:

      <div id="btn1">
          <div id="btn2">博客园</div>
      </div>

    例子: 1

      document.getElementById('btn1').addEventListener('click', foo1, false);
      document.getElementById('btn2').addEventListener('click, foo2, false);

      function foo1(event) {
        console.log(666);
      }
      function foo2(event) {
        console.log(888);
      }

      console.log:

      888
      666

      这里两个事件都是冒泡类型,所以是从内到外;

    例子: 2
      document.getElementById('btn1').addEventListener('click', foo1, true);
      document.getElementById('btn2').addEventListener('click', foo2, true);

      function foo1(event) {
        console.log(666);
      }
      function foo2(event) {
        console.log(888);
      }

      console.log:

      666
      888

      这里两个事件都是捕获类型,所以是从外到内;

    例子: 3
      document.getElementById('btn1').addEventListener('click', foo1, false);
      document.getElementById('btn2').addEventListener('click', foo2, true);

      function foo1(event) {
        console.log(666);
      }
      function foo2(event) {
        console.log(888);
      }

      console.log:

      888
      666

      btn1事件是冒泡,btn2 事件是捕获,根据 dom 的事件流,先执行了捕获阶段(这里是目标阶段)再到冒泡阶段。

    例子: 4

      document.getElementById('btn1').addEventListener('click', foo1, true);
      document.getElementById('btn2').addEventListener('click', foo2, false);

      function foo1(event) {
        console.log(666);
      }
      function foo2(event) {
        console.log(888);
      }

      console.log:

      666
      888

      btn2 事件是冒泡,btn1事件是捕获,根据 dom 的事件流,先执行了捕获阶段(这里是目标阶段)再到冒泡阶段。

    五. 阻止 冒泡/捕获

      <div id="btn1">
          <div id="btn2">博客园</div>
      </div>

      document.getElementById('btn1').addEventListener('click', foo1);
      document.getElementById('btn2').addEventListener('click', foo2);

      function foo1(event) {
        console.log(666);
      }
      function foo2(event) {
        event.stopPropagation();

      这样foo1中的代码就不会执行了,阻止冒泡
        console.log(888);
      }

    六. 事件委托

      事件委托是利用事件的冒泡原理来实现的,页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个冒泡机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。

    七. JS中事件兼容性封装

      Var  EventUtil={

    1.)添加事件方法

      addHandler:function(element,type,handler){

          if(element.addEventListener){

              element.addEventListener(type, handler, false);

      }else if (element.attachEvent){

              element.attachEvent("on" + type, handler);

          } else {

             element["on" + type] = handler;

          }

      }

    2.)移除之前添加的事件方法

      removeHandler:function(element, type, handler){ 

             if (element.removeEventListener){

                 element.removeEventListener(type, handler, false);

             } else if (element.detachEvent){

                 element.detachEvent("on" + type, handler);

             } else {

                 element["on" + type] = null;

             }

         }

    3.)获取事件及事件对象目标

       getEvent: function(event){

           return event ? event : window.event;

       },

       getTarget: function(event){

           return event.target || event.srcElement;

       }

    4.)阻止浏览器默认事件的兼容性写法

      preventDefault: function(event){ 

              if (event.preventDefault){

                  event.preventDefault();

              } else {

                  event.returnValue = false;

              }

          }

    5.)阻止事件冒泡的兼容性写法

      stopPropagation: function(event){ 

              if (event.stopPropagation){

                  event.stopPropagation();

              } else {

                  event.cancelBubble = true;

              }

          }

      }

      下面我就举一个例子演示一下用法:

        <button id=”btn”>点击事件</button>

        var btn=document.getElementById(“btn”);

        EventUtil.addHandler(btn,”click”,function(){

        console.log(“这是一次简单的演示”)

        })

  • 相关阅读:
    Linux系统中如何查找大文件或目录文件夹的方法
    SELinux 宽容模式(permissive) 强制模式(enforcing) 关闭(disabled) 几种模式之间的转换
    使用纯css代码实现div的“回”字型“叠放”效果
    中国剩余定理求解“六位教授必须首次都停止上课”问题
    Java基础篇Socket网络编程中的应用实例
    计算正互反矩阵的特征值及特征向量
    维吉尼亚密码java代码实现根据密钥长度计算IC值过程
    维吉尼亚密码java完整版
    容器常用操作注意事项
    HashMap源码分析
  • 原文地址:https://www.cnblogs.com/lbweb/p/6017658.html
Copyright © 2011-2022 走看看