【DOM】-- 事件机制

发布于:2023-01-04 ⋅ 阅读:(387) ⋅ 点赞:(0)

目录

DOM事件

事件的组成:(事件三要素)

执行步骤:

 常用事件:

 DOM事件流

事件流的分类

 冒泡型事件流:

阻止事件冒泡

 捕获型事件流

DOM事件流的三个阶段

事件处理程序

HTML事件处理程序

DOM0 事件处理程序

DOM2 事件处理程序

事件对象

阻止默认事件发生

preventDefault()方法

事件委托和事件代理


DOM事件

HTML DOM允许JS对HTML事件作出反应,当对某个元素进行操作时执行JavaScript代码。

JavaScript与HTML之间的交互是通过事件实现的。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。

事件的组成:(事件三要素)

  1. 事件源:事件被触发的对象 --- 按钮对象
  2. 事件类型:如和触发?触发什么事件?--- 鼠标点击,键盘按下……
  3. 事件处理程序:通过函数赋值

执行步骤:

  1. 获取事件源

  2. 绑定事件(注册事件)

  3. 采用函数赋值的方式添加事件处理程序 

 常用事件:

 DOM事件流

简单来说,事件流就是事件执行的顺序。DOM树里会有许多元素嵌套,当我们同时给父子元素设置了事件时,父子元素会以一种特定的顺序来执行事件,这就是事件流。并且嵌套的层级不限,事件会贯穿当前元素与根元素。

事件流的分类

DOM支持两种事件流:冒泡型事件流 | 捕获型事件流

  • 冒泡型事件流:从特定的事件目标到外层的不特定的元素,由下往上,从叶子节点到根节点。 即:某个具体的元素-> … -> body -> html -> document -> window
  • 捕获型事件流:从最外层不特定的事件目标到特定的事件目标,由上往下,从DOM的根节点到叶子节点。即:: window -> document -> html -> body -> … -> 某个具体的元素

 冒泡型事件流:

<style>
      * {
        color: white;
        font-size: 20px;
      }
      #outer {
        width: 300px;
        height: 300px;
        background-color: lightpink;
      }
      #center {
        width: 200px;
        height: 200px;
        background-color: lightgreen;
      }
      #inner {
        width: 100px;
        height: 100px;
        background-color: lightskyblue;
      }
    </style>
  </head>
  <body>
    <div id="outer">
      outer
      <div id="center">
        center
        <div id="inner">inner</div>
      </div>
    </div>
    <script>
      var inner = document.getElementById("inner");
      var center = document.getElementById("center");
      var outer = document.getElementById("outer");
      // 当我们只有一个inner点击方法的时候 我们发现想要实现的效果和我们预期的一样
      inner.onclick = function () {
        console.log("我是inner点击的");
      };
      // 但是当我们给inner的父元素和祖先元素也添加点击事件时 一点击inner 所有祖先元素的事件都会被触发,这就是事件冒泡现象
      center.onclick = function () {
        console.log("我是center点击的");
      };
      outer.onclick = function () {
        console.log("我是outer点击的");
      };
    </script>
  </body>

第一次只在 inner 上添加了事件,因此点击 inner 时只有 inner 上的事件被触发: 

 第二次我们在 center 和 outer 上也添加了点击事件,虽然我们只点击了 inner 但是 center 与 outer 上的事件也被触发了:

 事实上,这个click事件还会沿着DOM树一直到body,html,document。

阻止事件冒泡

在阻止冒泡之前,我们要知道一个对象叫 event ,它代表事件的状态,比如事件在其中发生的元素,键盘状态,鼠标位置,鼠标按钮状态等……

事件通常与函数结合使用,函数不会在事件发生前被执行!

直接在对应方法中使用 event.stopPropagation() 便可阻止事件冒泡。

注意:如果点击方法时需要同时传递其他参数和event,直接传递event这个单词即可

 捕获型事件流

在捕获型事件流中,click事件会首先被document捕获,然后沿着DOM树依次向下,直到事件的目标元素。

由于旧版本浏览器不支持,因此实际当中几乎不会使用事件捕获。通常建议使用事件冒泡,特殊情况下可以使用事件捕获。

DOM事件流的三个阶段

事件捕获、到达目标、事件冒泡

  1. 捕获阶段:从window对象依次向下传播,到达目标节点,即为捕获阶段。捕获阶段不会响应任何事件
  2. 目标阶段:在目标节点触发事件,即为目标阶段
  3. 冒泡阶段:从目标阶段依次向上传播,到达window对象,即为冒泡阶段。

事件处理程序

为响应事件而调用的函数被称为事件处理程序(或事件监听器)。事件处理程序的名字以"on"开头,因此 click 事件的处理程序叫作 onclick,而 load 事件的处理程序叫作 onload。有很多方式可以指定事件处理程序。

HTML事件处理程序

特定元素支持的每个事件都可以使用事件处理程序的名字以 HTML 属性的形式来指定。此时的属性值必须是能够执行的 JavaScript 代码。例如,要在按钮被点击时执行某些 JavaScript 代码,可以使用以下 HTML 属性:

<button onclick="console.log('Clicked')">点我啊</button>

点击这个按钮后,控制台会输出一条消息。

注意,因为属性的值是 JavaScript 代码,所以不能在未经转义的情况下使用 HTML 语法字符,比如和号(&)、双引号(")、小于号(<)和大于号(>)。此时,为了避免使用 HTML 实体,可以使用单引号代替双引号。如果确实需要使用双引号,则要把代码改成下面这样:

<button onclick="console.log(&quot;Clicked&quot;)">点我啊</button>

在 HTML 中定义的事件处理程序可以包含精确的动作指令,也可以调用在页面其他地方定义的方法。

<!-- 需要加() -->
<button onclick="showMsg()">点我啊</button>
<script>
  function showMsg() {
    console.log('Hello Wolrd!');
  }
</script>


在这个函数中,this 值相当于事件的目标元素,如下面的例子所示:

<button onclick="this.innerHTML = '我被改变了'">点我啊</button>

DOM 0级 事件处理程序 -- 事件不可以追加

要使用 JavaScript 指定事件处理程序,必须先取得要操作对象的引用。每个元素(包括 window 和 document)都有通常小写的事件处理程序属性,比如 onclick。只要把这个属性赋值为一个函数即可:

<button id="btn">点我</button>
    <script>
        // DOM0
        var btn = document.getElementById('btn')
        btn.onclick = function(event){
            console.log('我被打中了');    
            console.log(this.id); //btn

        }
     </script>

点击按钮,这段代码会显示元素的 ID。这个 ID 是通过 this.id 获取的。不仅仅是 id,在事件处理程序里通过 this 可以访问元素的任何属性和方法。以这种方式添加事件处理程序是注册在事件流的冒泡阶段的。在DOM2 中也如此。 

移除事件程序:

btn.onclick = null; // 移除事件处理程序

把事件处理程序设置为 null,再点击按钮就不会执行任何操作了。

DOM 2级 事件处理程序  -- 事件可以追加

DOM2 Events 为事件处理程序的赋值和移除定义了两个方法:

addEventListener()和removeEventListener()

这两个方法暴露在所有 DOM 节点上,它们接收 3 个参数:事件名、事件处理函数和一个布尔值,true 表示在捕获阶段调用事件处理程序,false(默认值)表示在冒泡阶段调用事件处理程序。

         <button id="btn">点我</button>
     <script>

        var btn = document.getElementById('btn')

        // 单纯添加事件处理程序
        btn.addEventListener('click',function(){
            console.log('怎么又被打中了');
        },false)
        btn.addEventListener('click',function(){
            console.log(this.id);  // btn
        })
    </script>

这里给按钮添加了两个事件处理程序。多个事件处理程序以添加顺序来触发,因此前面的代码会先打印'我被点击了',然后显示元素ID。

通过 addEventListener()添加的事件处理程序只能使用 removeEventListener()并传入与添加时同样的参数来移除。这意味着使用 addEventListener()添加的匿名函数无法移除,如:

<button id='btn'>点我啊</button>
<script>
  var btn = document.getElementById("btn");
  btn.addEventListener("click", function () {
    console.log('我被点击了');
  }, false);
  // 移除
  btn.removeEventListener("click", function () {
    console.log(this.id); //没有效果
  })
</script>

解绑事件要具名: 

 这个例子通过 addEventListener()添加了一个匿名函数作为事件处理程序。然后,又以看起来相同的参数调用了 removeEventListener()。但实际上,第二个参数与传给 addEventListener()的完全不是一回事。传给 removeEventListener()的事件处理函数必须与传给 addEventListener()的是同一个,如:

<button id='btn'>点我啊</button>
<script>
  var btn = document.getElementById("btn");
  // 新增一个方法
  var handler = function () {
    console.log(this.id);
  }
  btn.addEventListener("click", handler, false);
  // 移除
  btn.removeEventListener("click", handler, false); // 有效果
</script>

这个例子有效,因为调用 addEventListener()和 removeEventListener()时传入的是同一个函数。

事件对象

 在 DOM 中发生事件时,所有相关信息都会被收集并存储在一个名为 event 的对象中。这个对象包含了一些基本信息,比如导致事件的元素、发生的事件类型,以及可能与特定事件相关的任何其他数据。例如,鼠标操作导致的事件会生成鼠标位置信息,而键盘操作导致的事件会生成与被按下的键有关的信息。所有浏览器都支持这个 event 对象,尽管支持方式不同。

注意:event 对象只在事件处理程序执行期间存在,一旦执行完毕,就会被销毁。

阻止默认事件发生

preventDefault()方法

用于阻止特定事件的默认动作。比如,链接的默认行为就是在被单击时导航到 href 属性指定的 URL或是修改表单提交的默认事件。如果想阻止这些行为,可以在 onclick 事件处理程序中取消,如:

<form action="./1-class01.html">
        <button id="btn">提交</button>
    </form>
    <script>
        // 组织a事件的默认事件发生
        var a = document.getElementsByTagName('a')[0]
        a.onclick = function(event){
            event.preventDefault();
            console.log('a被点中了');
        }
        var f = document.getElementById('btn')
        btn.onclick = function(event){
            event.preventDefault();
            console.log('┗|`O′|┛ 嗷~~');
        }
    </script>

事件委托和事件代理


事件委托:也就是事件代理,也就是将原本绑定在子元素身上的事件 委托 给父元素。让父元素去监听事件。其原理是利用事件冒泡。这意味着可以为整个页面指定一个 onclick 事件处理程序,而不用为每个可点击元素分别指定事件处理程序。

优点:大大减少DOM操作和浏览器的重排和重绘,节省内存占用。也可以实现当新增对象时无需再次对其绑定事件。

如·:

 

 这里的 HTML 包含 3 个列表项,在被点击时应该执行某个操作。对此,通常的做法是像这样指定 3个事件处理程序:

 使用事件委托,只要给所有元素共同的祖先节点添加一个事件处理程序,就可以解决代码大段雷同的问题:

 这里只给<ul id="father">元素添加了一个 onclick 事件处理程序。因为所有列表项都是这个元素的后代,所以它们的事件会向上冒泡,最终都会由这个函数来处理。但事件目标是每个被点击的列表项,只要检查 event 对象的 id 属性就可以确定,然后再执行相应的操作即可。相对于前面不使用事件委托的代码,这里的代码不会导致先期延迟,因为只访问了一个 DOM 元素和添加了一个事件处理程序。结果对用户来说没有区别,但这种方式占用内存更少。所有使用按钮的事件(大多数鼠标事件和键盘事件)都适用于这个解决方案。
 

本文含有隐藏内容,请 开通VIP 后查看