当前位置: 首页 > news >正文

[JavaScript] JavaScript事件注册,事件委托,冒泡,捕获,事件流

面试题 event 事件

  • 事件委托是什么?
  • 如何阻止事件冒泡,阻止默认事件呢?
  • Javascript 的事件流模型都有什么?
  • 事件绑定和普通事件有什么区别?

event

Event 对象

Event 对象,当事件发生的时候出发某个函数,该 Event 对象将自动在函数内可用,该对象包含了很多事件触发时候的信息,
但 IE 却没有这么实现,而是自己实现的,IE 浏览器是通过全局对象 window 下的 event 属性来包含这些信息

function myEventHandler(e) {
    // 注意参数e
    // 该函数调用的时候e是event对象(W3C实现)
    // 兼容IE的代码
    e = e || window.event;
    // 现在e就可以兼容各种浏览器了
}

事件注册

这里最重要的就是 IE 的 attachEvent 和 W3C 标准 addEventListener 在执行上的一些区别

  1. attachEvent 只支持事件冒泡 addEventListener 既支持事件冒泡,也支持事件捕获
  2. 参数:attachEvent 事件类型需要 on 前缀 addEventListener 事件类型不需要 on 前缀
  3. 如果使用 attachEvent 对一个元素的目标阶段绑定了多次事件,那么会按照绑定顺序的相反顺序进行触发。如果使用 addEventListener 对一个元素的目标阶段绑定了多次事件,那么会按照绑定顺序进行触发

w3c

var oBtn = document.getElementById("btn1");
oBtn.addEventListener('click', introClick, false);

ie

var oBtn = document.getElementById("btn1");
oBtn.attachEvent('onclick', introClick);

兼容写法

      var oBtn = document.getElementById("btn1");
      addEvent(oBtn, "click", show);
      addEvent(oBtn, "click", show2);
      // removeEvent(oBtn, "click", show);

      //对象.addEventListener(事件名,函数,false);  for 高
      //事件名 onclick over/out/down/up.........不带on
      //函数  obj.onclick=show    show==函数
      function addEvent(obj, eve, fn) {
        if (obj.addEventListener) {
          obj.addEventListener(eve, fn, false); //由于事件参数不带on
        } else {
          obj.attachEvent("on" + eve, fn); //所以这里的绑定事件要将on补上
        }
      }

      //解绑
      //对象.removeEventListener(事件名,函数,false);  chrome FF IE 9 10
      //对象.detachEvent(事件名,函数);        IE 6 7 8
      // oBtn.detachEvent('onclick',show2);
      //移除函数
      function removeEvent(obj, eve, fn) {
        if (obj.removeEventListener) {
          obj.removeEventListener(eve, fn, false);
        } else {
          obj.detachEvent("on" + eve, fn);
        }
      }

      function show() {
        alert("我将弹出1");
      }

      function show2() {
        alert("我将弹出2");
      }

删除匿名函数的引用

addEvent(oBtn, 'click', function(){
    alert("弹出1");
    //arguments对象包含了所有传递进来的参数以及该函数自身(callee)
    console.log(arguments);
    removeEvent(oBtn, 'click', arguments.callee);
});

arguments对象

W3C 和微软模型还有其他的少许差异,callee 是返回正在被执行的 function 函数,也就是所指定的 function 对象的正文。arguments.callee 知道就好了,别在代码中用了

事件冒泡和捕获

当年,IE 是冒泡流,而网景是捕获流,W3C 费些力使 JS 支持了冒泡流和捕获流。但是前些年或者更之前的时候,IE 还是老大,于是早期的 IE 浏览器并不支持捕获。

冒泡

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>事件冒泡</title>
    <style></style>
    <script>
      window.onload = function() {
        _id("div1").addEventListener(
          "click",
          function() {
            alert(_id("div1").style.background);
          },
          false
        );

        _id("div2").addEventListener(
          "click",
          function() {
            alert(_id("div2").style.background);
          },
          false
        );

        _id("div3").addEventListener(
          "click",
          function() {
            alert(_id("div3").style.background);
          },
          false
        );

        function _id(id) {
          return document.getElementById(id);
        }
      };
    </script>
  </head>

  <body>
    <div id="div1" style="width:500px; height:500px; background:red;">
      <div id="div2" style="height:300px; width:300px; background:yellow">
        <div id="div3" style="width:100px; height:100px; background:blue"></div>
      </div>
    </div>
  </body>
</html>

捕获

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>事件捕获</title>
    <style></style>
    <script>
      window.onload = function() {
        var oDiv1 = document.getElementById("div1");
        var oDiv2 = document.getElementById("div2");
        var oDiv3 = document.getElementById("div3");

        oDiv1.addEventListener(
          "click",
          function() {
            alert(oDiv1.style.background);
          },
          true
        );

        oDiv2.addEventListener(
          "click",
          function() {
            alert(oDiv2.style.background);
          },
          true
        );

        oDiv3.addEventListener(
          "click",
          function() {
            alert(oDiv3.style.background);
          },
          true
        );
      };
    </script>
  </head>

  <body>
    <div id="div1" style="width:500px; height:500px; background:red;">
      <div id="div2" style="height:300px; width:300px; background:yellow">
        <div id="div3" style="width:100px; height:100px; background:blue"></div>
      </div>
    </div>
  </body>
</html>

addEventListener 的第三个参数 true 就是捕获,false 就是冒泡

阻止默认行为

    <script type="text/javascript">
      var oBtn = document.getElementById("btn1");
      addEvent(oBtn, "click", myEventHandler);

      //对象.addEventListener(事件名,函数,false);  for 高
      //事件名 onclick over/out/down/up.........不带on
      //函数  obj.onclick=show    show==函数
      function addEvent(obj, eve, fn) {
        if (obj.addEventListener) {
          obj.addEventListener(eve, fn, false); //由于事件参数不带on
        } else {
          obj.attachEvent("on" + eve, fn); //所以这里的绑定事件要将on补上
        }
      }

      function myEventHandler(e) {
        e = e || window.event;
        // 防止默认行为
        if (e.preventDefault) {
          e.preventDefault();
        } else {
          e.returnValue = false;
        }
      }
    </script>

禁止一下鼠标右键

    document.getElementById("contextmenu").addEventListener(
      "contextmenu",
      function(ev) {
        var oEvt = ev || event;
        oEvt.preventDefault(); //阻止默认
      },
      false
    );

阻止冒泡

<script>
      window.onload = function() {
        _id("div1").addEventListener(
          "click",
          function() {
            alert(_id("div1").style.background);
          },
          false
        );

        _id("div2").addEventListener(
          "click",
          function() {
            alert(_id("div2").style.background);
          },
          false
        );

        _id("div3").addEventListener("click", myParagraphEventHandler, false);

        function _id(id) {
          return document.getElementById(id);
        }

        function myParagraphEventHandler(e) {
          alert(this.style.background);
          e = e || window.event;
          // 停止向上冒泡
          if (e.stopPropagation) {
            // W3C实现
            e.stopPropagation();
          } else {
            // IE实现
            e.cancelBubble = true;
          }
        }
      };
    </script>

为什么我们要阻止默认事件呢?

  1. 异步操作
  2. 提交表单之前对表单进行一些基本的验证,比如邮箱是否合法,用户名是不是满足指定的格式,为了不让 a 点击之后跳转,我们就要给他的点击事件进行阻止
  3. 文本框获得焦点

事件委托

事件委托描述的是将事件绑定在容器元素上,然后通过判断点击的 target 子元素的类型来触发相应的事件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <table id="my-table">
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>4</td>
        <td>5</td>
        <td>6</td>
      </tr>
      <tr>
        <td>7</td>
        <td>8</td>
        <td>9</td>
      </tr>
      <tr>
        <td>11</td>
        <td>22</td>
        <td>33</td>
      </tr>
      <tr>
        <td>44</td>
        <td>55</td>
        <td>66</td>
      </tr>
    </table>
  </body>
  <script>
    var myTable = document.getElementById("my-table");

    myTable.onclick = function(e) {
      // 处理浏览器兼容
      e = e || window.event;
      var targetNode = e.target || e.srcElement;

      if (targetNode.nodeName.toLowerCase() === "td") {
        alert("You clicked a table row!");
      }
    };
  </script>
</html>

DOM 事件流

这就是为什么捕获事件中,目标阶段是最后。而在冒泡事件中,目标阶段是最先了

DOM 事件流

面试题答案

  • 利用事件冒泡的原理,让自己的所触发的事件,让他的父元素代替执行 2.阻止冒泡 ie 是 ;其他是;

  • 浏览器阻止冒泡阻止默认
    ieev.cancelBubble = truereturn false
    其他ev.stopPropagation()ev.preventDefault()
  • "事件冒泡":事件开始由最具体的元素接受,然后逐级向上传播
    "事件捕捉":事件由最不具体的节点先接收,然后逐级向下,一直到最具体的
    "DOM 事件流":三个阶段:事件捕捉,目标阶段,事件冒泡

  • xxx.onEvent = function(){}其实是赋值操作,下面取缔上面的。而事件绑定可以一口气绑定多个事件,按绑定顺序执行

xxx.onEvent 就是对监听属性赋值一个函数,取消绑定设置为空就好了 xxx.onEvent = null

常见事件

鼠标事件

  • mousedown 鼠标设备按下一个元素的时候触发 mousedown 事件
  • mouseup 鼠标设备从按下的元素上弹起的时候触发 mouseup 事件
  • click 鼠标点击元素的时候触发 click 事件
  • dblclick 鼠标双击元素的时候触发 dblclick 事件
  • mouseover 鼠标移动到某元素上的时候触发 mouseover 事件
  • mouseout 鼠标从某元素离开的时候触发 mouseout 事件
  • mousemove 鼠标在某元素上移动但未离开的时候触发 mousemove 事件

键盘事件

  • keypress 按键按下的时候触发该事件
  • keydown 按键按下的时候触发该事件,并且在 keypress 事件之前
  • keyup 按键松开的时候触发该事件,在 keydown 和 keypress 事件之后

表单事件

  • select 文本字段(input, textarea 等)的文本被选择的时候触发该事件
  • change 控件失去 input 焦点的时候触发该事件(或者值被改变的时候)
  • submit 表单提交的时候触发该事件
  • reset 表单重置的时候触发该事件
  • focus 元素获得焦点的时候触发该事件,通常来自鼠标设备或 Tab 导航
  • blur 元素失去焦点的时候触发该事件,通常来自鼠标设备或 Tab 导航

其它事件

  • load 页面加载完毕(包括内容、图片、frame、object)的时候触发该事件
  • resize 页面大小改变的时候触发该事件(例如浏览器缩放)
  • scroll 页面滚动的时候触发该事件
  • unload 从页面或 frame 删除所有内容的时候触发该事件(例如离开一个页面)

参考

MDN - addEventListener
JavaScript 权威指南(第 5 版)

转载于:https://www.cnblogs.com/mybilibili/p/10444309.html

相关文章:

  • ML_SVM算法
  • 第一周作业
  • 来一局紧张刺激的吃鸡——浅谈装饰者模式
  • python爬虫之selenium,谷歌无头浏览器
  • 100道C#面试题(.net开发人员必备)
  • P1601 A+B Problem(高精)
  • redis、mysql、mongdb的比较
  • PAT基础6-12
  • bzoj3684: 大朋友和多叉树(拉格朗日反演+多项式全家桶)
  • 关于 RESTful API 中 HTTP 状态码的定义
  • 第一章:打印直方图
  • 第九届蓝桥杯省赛--方格计数
  • 数列分块(数据结构)学习笔记
  • 程序员:想知道你每天按了多少次键盘吗?
  • 分布式和集群的区别
  • Brief introduction of how to 'Call, Apply and Bind'
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • git 常用命令
  • k8s如何管理Pod
  • Laravel5.4 Queues队列学习
  • Making An Indicator With Pure CSS
  • ng6--错误信息小结(持续更新)
  • scrapy学习之路4(itemloder的使用)
  • storm drpc实例
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 前端js -- this指向总结。
  • 前端攻城师
  • 前端面试之闭包
  • 项目实战-Api的解决方案
  • 优化 Vue 项目编译文件大小
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • #Linux(make工具和makefile文件以及makefile语法)
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (C语言)字符分类函数
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (十) 初识 Docker file
  • (原創) 博客園正式支援VHDL語法著色功能 (SOC) (VHDL)
  • (转)scrum常见工具列表
  • (转)拼包函数及网络封包的异常处理(含代码)
  • ******之网络***——物理***
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .NET CF命令行调试器MDbg入门(一)
  • .NET delegate 委托 、 Event 事件
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .NET/MSBuild 中的发布路径在哪里呢?如何在扩展编译的时候修改发布路径中的文件呢?
  • .NET框架设计—常被忽视的C#设计技巧
  • .NET企业级应用架构设计系列之技术选型
  • /bin、/sbin、/usr/bin、/usr/sbin
  • /deep/和 >>>以及 ::v-deep 三者的区别
  • [ C++ ] STL---stack与queue
  • [23] 4K4D: Real-Time 4D View Synthesis at 4K Resolution
  • [C#]C# OpenVINO部署yolov8图像分类模型
  • [c]扫雷
  • [CentOs7]iptables防火墙安装与设置