2.03.11event对象,事件冒泡与捕获

2.03.11event对象 事件冒泡与捕获

1.Event对象

  1. 概念
  • 事件对象记录了数据出触发时产生的数据集合
  • 记录了事件的信息(状态、信息、事件类型)
  • 有时候在事件处理函数内部,您可能会看到一个固定指定名称的参数,例如event,evt或简单的e。 这被称为事件对象,它被自动传递给事件处理函数,以提供额外的功能和信息。简单的说Event对象是事件执行过程中的状态,用来保存当前事件的信息对象
  • 比如,你点击鼠标事件触发点击事件,事件对象会记录你,是否按着alt键点击鼠标,是否按着shift键点击鼠标等
  • 例子:
<button>Change color</button>

<script>

    const btn = document.querySelector('button');

    btn.addEventListener('click', bgChange);

    function random(number) {
    return Math.floor(Math.random()*(number+1));
    }
    // 在函数中包括一个事件对象e
    function bgChange(e) {
    const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
    // 并在函数中设置背景颜色样式在e.target上 - 它指的是按钮本身
    e.target.style.backgroundColor = rndCol;
    console.log(e);
    }
</script>
  • 注意产生event对象的事件函数的参数列表
	 <div class="test" style="width: 50px;height: 50px;background-color: red;"> </div>
	<script>
        document.querySelector(".test").onmouseenter=function(a,b=2){
            console.log(arguments);//Argrments[event]
            console.log(a);//event对象
            console.log(a===arguments[0]);//true
            console.log(a===event);//true
            console.log(arguments[1]);//undefined
            console.log(b);//2
        }
    </script>
  1. Event公共属性与方法
  • currentTarget 其事件处理程序当前正在处理事件的那个元素
  • target 返回触发此事件的元素(事件的目标元素)
  • type 被触发的事件类型
  • preventDefault() 通知浏览器不要执行与事件相关联的默认动作.
  • stopPropagation() 取消事件进一步捕获或者冒泡
  1. 鼠标/键盘事件Event属性
  • altKey 返回当前事件触发时,'ALT’是否被按下
  • ctrlKey 返回当前事件触发时,'Ctrl’是否被按下
  • shiftKey 返回当前事件触发时,'Shift’是否被按下
  • button 返回当前事件被触发时,鼠标那个按钮被点击
  • which 该属性声明了被敲击的键生成的ascii码 字符码
  • keyCode 该属性声明了被敲击的键生成的ascii码 字符码
  • clientX 返回当事件被触发时,鼠标指针相对于浏览器可视区域的水平坐标
  • clientY 返回当事件被触发时,鼠标指针相对于浏览器可视区域的垂直坐标
  • screenX 返回当某个事件被触发时,鼠标指针相对于电脑屏幕的水平坐标
  • screenY 返回当某个事件被触发时,鼠标指针相对于电脑屏幕的垂直坐标
  • pageX,PageY 鼠标相对于文档的位置(包括滚动条的距离,即clientX+document.body.scrollLeft,IE不支持)
  • offsetX,offsetY 返回发生事件的地点在事件源元素的坐标系统中的x坐标和y坐标

2.阻止默认行为

  • 介绍:默认行为就是浏览器自己触发的事件。比如:a链接的跳转,表单的提交,鼠标右键菜单显示。
  • 方法:阻止浏览器的默认行为 event.preventDefault();
  • 例子:
    /*
    思考:有时,你会遇到一些情况,你希望事件不执行它的默认行为。 最常见的例子是Web表单,例如自定义注册表单。 当你填写详细信息并按提交按钮时,自然行为是将数据提交到服务器上的指定页面进行处理,并将浏览器重定向到某种“成功消息”页面,当用户没有正确提交数据时,麻烦就来了 - 作为开发人员,你希望停止提交信息给服务器,并给他们一个错误提示,告诉他们什么做错了,以及需要做些什么来修正错误。 一些浏览器支持自动的表单数据验证功能,但由于许多浏览器不支持,因此建议你不要依赖这些功能,并实现自己的验证检查。
    */
    /*
    首先,一个简单的HTML表单,需要你填入名(first name)和姓(last name)
    */

    <form>
        <div>
            <label for="fname">First name: </label>
            <input id="fname" type="text">
        </div>
        <div>
            <label for="lname">Last name: </label>
            <input id="lname" type="text">
        </div>
        <div>
            <input id="submit" type="submit">
        </div>
    </form>
    <p></p>

    /*
    这里我们用一个onsubmit事件处理程序(在提交的时候,在一个表单上发起submit事件)来实现一个非常简单的检查,用于测试文本字段是否为空。 如果是,我们在事件对象上调用preventDefault()函数,这样就停止了表单提交,然后在我们表单下面的段落中显示一条错误消息,告诉用户什么是错误的:
    */

    const form = document.querySelector('form');
    const fname = document.getElementById('fname');
    const lname = document.getElementById('lname');
    const submit = document.getElementById('submit');
    const para = document.querySelector('p');

    form.onsubmit = function(e) {
        if (fname.value === '' || lname.value === '') {
            e.preventDefault();
            para.textContent = '你需要把两个名字都填上!';
        }
    }

3.事件的冒泡与捕获

1. 概念

  • 事件冒泡和捕捉是两种机制,主要描述当在一个元素上有两个相同类型的事件处理器被激活会发生什么。当一个事件发生在具有父元素的元素上时,现代浏览器运行两个不同的阶段 - 捕获阶段和冒泡阶段。
  • 在捕获阶段:
    • 浏览器检查元素的最外层祖先 html ,是否在捕获阶段中注册了一个onclick事件处理程序,如果是,则运行它。
    • 然后,它移动到 html 中单击元素的下一个祖先元素,并执行相同的操作,然后是单击元素再下一个祖先元素,依此类推,直到到达实际点击的元素
  • 在冒泡阶段,恰恰相反:
    • 浏览器检查实际点击的元素是否在冒泡阶段中注册了一个onclick事件处理程序,如果是,则运行它
    • 后它移动到下一个直接的祖先元素,并做同样的事情,然后是下一个,等等,直到它到达 html 元素。

请添加图片描述

  • 注意:在现代浏览器中,默认情况下,所有事件处理程序都在冒泡阶段进行注册。因此,在上面的图示中,当您单击 video 时,这个单击事件从 video 元素向外冒泡直到 html 元素。
  • 注意:只有点击容器重叠部分才会有事件的两种机制的触发。

2. 阻止事件冒泡/捕获

  1. 概念:标准事件对象Event具有可用的名为 stopPropagation() 的函数, 当在事件对象上调用该函数时,它只会让当前事件处理程序运行,但事件不会在冒泡/捕获链上进一步扩大,因此将不会有更多事件处理器被运行不会继续冒泡/捕获。
  • 用法:
    video.onclick = function(e) {
        e.stopPropagation();
    };
  1. 注意:
  • 默认情况下,绝大多数事件处理程序都是在冒泡阶段注册的,这在大多数情况下更有意义。如果您真的想在捕获阶段注册一个事件,那么您可以通过使用addEventListener()注册您的处理程序,并将可选的第三个属性设置为true。
  • 不是所有的事件都能冒泡,以下事件不能冒泡:blur,focus,load,unload…
  • 冒泡到最顶层的目标不同,大部分浏览器到window,IE8到document
    什么是事件的冒泡:
       在一个对象上触发某类事件(如click事件),那么click事件就会向这个事件的父级传播,从里到外,直到他被处理程序处理,或者事件到达最顶层(document/window)
    冒泡的阻止:
    event.stopPropagation();
    e.stopPropagation? e.stopPropagation(): e.cancelBubble = true 
    //判断是否有 e.stopPropagation()?这个事件
    1) 如果存在该事件执行该事件,事件将不再继续传递。
    2) 如果不存在,使用event.cancelBubble=true 取消事件处理,兼容写法在 IE 的事件机制中,触发事件会从子元素向父元素逐级上传,就是说,如果子元素触发了单击事件,那么也会触发父元素的单击事件;event.cancelBubble=true;可以停止事件继续上传
  • event.stopImmediatePropagation() 方法可以单单阻止事件捕获;
  • event.cancelBubble = true 方法可以单单阻止事件冒泡;
  • event.stopPropagation(); 方法可以阻止事件冒泡或者捕获;

4. 事件委托

  1. 概念:冒泡还允许我们利用事件委托,事件委托是通过事件冒泡这种方式,利用父级元素(或祖先元素)将事件监听器设置在其父级元素上,从而让其子元素(或后代元素)都绑定事件(注册事件)而不是每个子节点单独设置事件监听器。优势在于减少使用循环 减少DOM操作(节省内存) 动态给所有子元素或后代元素绑定事件
  2. 例子:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Useful event target example</title>
    <style>
      div {
        background-color: red;
        height: 100px;
        width: 25%;
        float: left;
      }
    </style>
  </head>
  <body>
    <script>
      for(let i = 1; i <= 16; i++) {
        const myDiv = document.createElement('div');
        document.body.appendChild(myDiv);
      }

      function random(number) {
        return Math.floor(Math.random() * number);
      }

      function bgChange() {
        const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
        return rndCol;
      }

      const divs = document.querySelectorAll('div');

     
      // for(let i = 0; i < divs.length; i++) {
      //   divs[i].onclick = function(e) {
      //     e.target.style.backgroundColor = bgChange();
      //   }
      // }
      // 这里无需循环给每个元素绑定事件,而是使用事件委托将点击事件绑定给他们的父元素
      document.body.onclick = function(e) {
        // 通过e.target 判断是否是需要变色的元素
          if(e.target.tagName.toLowerCase()=="div") {
            e.target.style.backgroundColor = bgChange();
          }
      }

    </script>
  </body>
</html> 
  • 注意:一般事件委托的监听函数里面都有个if条件去判断该不该执行后面的代码,因为委托的事件使得多个容器都可以触发事件函数,避免别的不是目标容器的点击也把事件函数触发了

5. 节点的克隆

  1. 介绍:cloneNode(all) 方法创建节点的拷贝,并返回该副本。
  2. 语法:var dupNode = node.cloneNode(all);
    • node:将要被克隆的节点
    • dupNode:克隆生成的副本节点
    • all (可选):是否采用深度克隆,如果为true,则该节点的所有后代节点也都会被克隆,如果为false,则只克隆该节点本身.
  3. 用法:
    var p = document.getElementById("para1"),
    var p_prime = p.cloneNode(true);
  1. 补充:
  • 克隆一个元素节点会拷贝它所有的属性以及属性值,当然也就包括了属性上绑定的事件(比如οnclick=“alert(1)”),但不会拷贝那些使用addEventListener()方法或者node.onclick = fn这种用JavaScript动态绑定的事件.

  • 在使用Node.appendChild()或其他类似的方法将拷贝的节点添加到文档中之前,那个拷贝节点并不属于当前文档树的一部分,也就是说,它没有父节点.

  • 如果deep参数设为false,则不克隆它的任何子节点.该节点所包含的所有文本也不会被克隆,因为文本本身也是一个或多个的Text节点.

  • 如果deep参数设为true,则会复制整棵DOM子树(包括那些可能存在的Text子节点).对于空结点(例如 img 和 input 标签元素),则deep参数无论设为true还是设为false,都没有关系,但是仍然需要为它指定一个值.

  1. 注意:
    • 为了防止一个文档中出现两个ID重复的元素,使用cloneNode()方法克隆的节点在需要时应该指定另外一个与原ID值不同的ID
    • 如果原始节点设置了ID,并且克隆节点会被插入到相同的文档中,那么应该更新克隆节点的ID以保证唯一性。name属性可能也需要进行修改,取决于你是否希望有相同名称的节点存在于文档中。

t 标签元素),则deep参数无论设为true还是设为false,都没有关系,但是仍然需要为它指定一个值.

  1. 注意:
    • 为了防止一个文档中出现两个ID重复的元素,使用cloneNode()方法克隆的节点在需要时应该指定另外一个与原ID值不同的ID
    • 如果原始节点设置了ID,并且克隆节点会被插入到相同的文档中,那么应该更新克隆节点的ID以保证唯一性。name属性可能也需要进行修改,取决于你是否希望有相同名称的节点存在于文档中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值