【DOM】DOM事件全解析,万字总结,看这一篇文章就够了_07

目录

❣️ 写在前头

❣️ DOM事件 

1. 复习: 事件简介

2. 绑定事件: 3种

3. 事件模型: 高频鄙视题

4. 事件对象

❣️ 常用到的事件

⬛ 总结: DOM 5件事: 增删改查+事件绑定 

💦 DOM回顾:DOM入门基础全解析


❣️ 写在前头

事件是DOM中最重要的知识,可以这么说,我们之前讲的DOM的增删改查操作,一旦到了学了框架或者将来到了公司当中,可能就不用了,但我们不可以不学,因为我们学DOM是为了学框架打基础,学DOM有助于你对框架的理解,对一些API和实现原理的理解。另外,毕竟框架也不是万能的,我们谁也确定不了一个流行框架能活跃多长时间,所以,不管以后框架怎么变,但基础的还是基础,就像学习了自动挡开车之后,万一有一天只有手动挡的车,你该怎么办呢?

所以,说句认亲的话,你爹地始终是你爹地,这永远不会变,而且在框架的内部还是要操作DOM的。在这里,明着告诉大家,事件将来无论走到哪都会用,而且无论将来你学到哪个阶段,无论将来你去到哪个公司,只要你用事件,你用的都是本文即将要介绍的知识点,希望能帮到大家!

 

❣️ DOM事件 

1. 复习: 事件简介

         (1). 什么是事件: 用户手动触发的或浏览器自动触发的页面内容和状态的改变

        (2). 事件属性: 每个元素身上都有一批"on事件名"的属性。每当当前元素身上发生一个事件时,浏览器都会自动找到这个元素身上的对应的"on事件名"属性。自动触发该属性上提前保存的事件处理函数。

         (3). 事件绑定: 提前将要执行的函数,保存到一个元素的一个事件属性上。

         (4). 如何: 元素.on事件名=function(){ ... this ... } 

    这里的 this指代正在触发事件的当前元素对象本身 

2. 绑定事件: 3种

         (1). 在HTML中绑定:

         a. js中: 提前定义function 函数名(){ ... }

         b. html中: <元素 on事件名="函数名()">

         c. 问题: 不符合内容与行为分离的原则!及其不便于维护!      

    如果html元素藏的很深,且函数名改了怎么办,很难找

         (2). 在js中用赋值方式绑定:

         a. js中: 元素.on事件名=function(){ ... }

         b. 优点: 所有事件绑定都集中定义在js中,极其便于维护!

         c. 问题: 一个元素的一个事件属性上,只能绑定一个处理函数。无法同时绑定多个事件处理函数——不灵活!

         (3). 在js中通过添加事件监听对象的方式来绑定:

         a. js中: 元素.addEventListener("事件名", 事件处理函数)

                              添加 事件  监听对象

         b. 意为: 创建一个事件监听对象,其中包括3样东西:

                  1). 哪个元素

                  2). 哪个事件

                  3). 事件处理函数是什么

                  然后,浏览器会自动将事件监听对象加入到浏览器内存中一个巨大的事件监听队列中

         c. 结果:

                  1). 每当元素上发生事件时,浏览器都会自动遍历事件监听对象队列。

                  2). 查找和本次发生事件的元素、事件名相同的监听对象。

                  3). 只要找到的符合要求的监听对象,就自动触发监听对象中保存的事件处理函数

         d. 强调:

                  1). 其实在DOM标准中的事件名称都不带on开头:

                  比如: click单击   dblclick双击   mouseover鼠标进入   blur失去焦点  ...

                  所以. addEventListener("事件名")也不需要加on前缀

                  2). 但是元素对象身上的事件属性都带on

                        为了和元素身上其它普通的属性区分

凡是带on的是事件属性如onclick等,不带on的是普通的字符串属性如id、title、href)

         e. 移除事件监听对象:

                  1). 元素.removeEventListener("事件名", 原事件处理函数对象)

                 移除  事件 监听对象

                  2). 坑: 移除事件监听的原理:

                  i. 浏览器会去事件监听对象队列中查找要移除的事件监听对象:

                 ii. 如果发现一个事件监听对象的元素、事件名、事件处理函数的地址(处理函数是引用类型的对象,function()等于new function(),届时它会在内存中创建一个函数对象,然后这个函数对象有它的地址值,所以它放入事件监听对象的其实是一个地址值,于是然后它把这个事件监听对象放入了事件监听队列中)与removeEventListener()提供的参数值一致,就会移除该事件监听。

                iii. 但是, 如果绑定事件处理函数时,使用的是匿名函数绑定的!一旦绑定之后,就再不可能找到原函数对象了!移除时,也就不可能用原函数对象来移除原事件监听。

                  3). 解决: 今后如果一个事件监听对象有可能被移除,则不要用匿名函数绑定!应该用有名称的函数绑定。

                  4). 坑: 一旦添加事件监听时,使用有名称的函数来添加事件监听,则不允许重复添加一模一样的监听对象!

因为事件监听队列里已经有名为shoot2的函数地址,DOM不允许再次创建同名函数放进事件监听队列里)

                  5). 所以:

                  i. 如果使用匿名函数添加事件监听:

                  好处: 可反复添加多个; 不好: 无法移除

                  ii. 如果使用有名称的函数添加事件监听:

                  好处: 可移除; 不好: 只能加一个

                  6). 解决: jQuery  

                  jq中,即使使用有名称的函数添加事件监听,照样可以添加多个!移除时,只需要一次off,就可把所有同名的事件处理函数移除掉!$元素.off("事件名",事件处理函数名)。具体详解,请参考我之后jQuery关于事件绑定的介绍

         f. 示例: 添加移除事件监听对象:

         1_addEventListener.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>...</title>
    <script></script>
  </head>

  <body>
    <button id="btnShoot">shoot</button><br />
    <button id="btnAward">获得跟踪导弹</button><br />
    <button id="btnBreak">失去跟踪导弹</button><br />
    <script>
      var btnShoot = document.getElementById("btnShoot");
      var btnAward = document.getElementById("btnAward");
      var btnBreak = document.getElementById("btnBreak");
      //给btnShoot绑定单击事件处理函数,可发射普通子弹
      btnShoot.onclick = function () {
        console.log(`发射普通子弹......`);
      };
      //先定义一个发射跟踪导弹的有名称的函数
      function shoot2() {
        alert("发射跟踪导弹=>=>=>");
      }
      //当单击btnAward时,不是发生导弹,而是给btnShoot按钮再多绑定一种跟踪导弹
      btnAward.onclick = function () {
        //不能再用onclick=function(){ ... }
        // btnShoot.onclick=function(){
        //    alert("发射跟踪导弹=>=>=>");
        // }
        //向浏览器的事件监听对象的队列中添加了一个新的监听对象,元素:btnShoot, 事件名:click。
        btnShoot.addEventListener("click", shoot2);
      };
      //单击btnBreak时,从btnShoot上移除发射跟踪导弹的事件监听对象
      btnBreak.onclick = function () {
        btnShoot.removeEventListener("click", shoot2);
      };
    </script>
  </body>
</html>

运行结果: 

效果演示:

补:示例:匿名函数作为事件监听对象的事件处理函数

0_addEventListener.html

<!DOCTYPE html>
<html>
<head>
   <meta charset="utf-8" />
   <title>匿名函数作为事件监听对象的事件处理函数</title>
   <script>
   </script>
</head>

<body>
   <button id="btnShoot">shoot</button><br>
   <button id="btnAward">获得跟踪导弹</button><br>
   <button id="btnBreak">失去跟踪导弹</button><br>
   <script>
      var btnShoot=document.getElementById("btnShoot");
      var btnAward=document.getElementById("btnAward");
      var btnBreak=document.getElementById("btnBreak");
      //给btnShoot绑定单击事件处理函数,可发射普通子弹
      btnShoot.onclick=function(){
         console.log(`发射普通子弹......`)
      }

      //当单击btnAward时,不是发生导弹,而是给btnShoot按钮再多绑定一种跟踪导弹
      btnAward.onclick=function(){
         //不能再用onclick=function(){ ... }
         // btnShoot.onclick=function(){
         //    alert("发射跟踪导弹=>=>=>");
         // }
         // 向浏览器的事件监听对象的队列中添加了一个新的监听对象,元素:btnShoot, 事件名:click。
        //  点击多次获得跟踪导弹,再点击一次shoot按钮,会有多次发射跟踪导弹=>
        //  也就是说使用匿名函数添加事件监听,可反复添加多个

         btnShoot.addEventListener(
            "click",
             function(){
               alert("发射跟踪导弹=>=>=>")
             }
         )
      }
      //单击btnBreak时,从btnShoot上移除发射跟踪导弹的事件监听对象
      // 如果使用匿名函数添加事件监听,无法移除

      btnBreak.onclick=function(){
         btnShoot.removeEventListener(
            "click",
            function(){
               alert("发射跟踪导弹=>=>=>")
             }
         )
      }
   </script>
</body>
</html>

效果演示: 

3. 事件模型: 高频鄙视题


        (1). 什么是: 从刚触发事件,到所有事件处理函数执行完,所经历的完整过程。

❓ 你是否也有这样的疑惑:不是说点击一个元素就触发一个事件处理函数吗?什么叫所有事件处理函数都执行完?只点击了内部的d3,但是却有3个事件处理函数执行,这是怎么回事呢?这就涉及到了DOM的事件模型的3个阶段

         (2). DOM标准中的事件模型:3个阶段

         —— 事件捕获、事件触发(目标触发)、事件冒泡 ——

         a. 捕获: (DOM事件捕获的具体流程)浏览器会从顶级父元素document->html->body->...(按照DOM 结构一层层传递)->目标元素,开始由外向内依次遍历当前点击的元素的各级父元素。在遍历过程中,记录哪些父元素上绑定了相同的事件处理函数。——只记录不执行!

         b. 目标触发: 浏览器总是优先触发实际点击的这个元素上的事件处理函数。实际点击的元素,也被称为"目标元素"(target)

         c. 冒泡: 由内向外,依次触发各级父元素上的事件处理函数
         (——这就是为什么点击d3时,d2、d1都跟着喊疼,因为冒泡到了d2、d1身上)

  

DOM事件流相当于将事件捕获与事件冒泡两者结合起来,事件触发的顺序是先进行事件捕获阶段 => 目标元素阶段 => 事件冒泡阶段。

总结:事件函数执行顺序——捕获阶段的处理函数最先执行,其次是目标阶段的处理函数,最后是冒泡阶段的处理函数。目标阶段的处理函数,先注册(绑定)的先执行,后注册(绑定)的后执行。事件阻止只能阻止后续的阶段事件并且未作用于同一元素上的事件函数。 

 如果不想要事件模型怎么办?即不想要这个事件模型的默认行为和执行过程,也就是不想冒泡(就想点谁谁喊疼,没点你就不要凑热闹),这就需要用事件对象了👇

4. 事件对象

         (1). 什么是: 专门保存事件发生时的信息,并提供了修改属性默认行为的方法,的对象。

         (2). 何时: 2个

         a. 想获得事件发生时的信息时

         (——比如事件发生时鼠标点在哪个位置等等,这些信息就保存在事件对象中)

         b. 想改变事件默认的执行过程时

         (3). 如何获取:

         a. 事件对象是浏览器在事件发生时自动创建的,所以不用我们自己创建

         b. 所有事件对象都默认作为事件处理函数的第一个实参值自动传入

         c. 所以,要想接住事件对象,只要在事件处理函数中定义第一个形参变量等着即可!

                    浏览器自动创建event事件对象

                                                     ↓

                  元素.οnclick=function(e){

                          ... ...

               }

                  或

                  元素.addEventListener("click",function(e){ ... })

         (4). 接住事件对象后能干什么:

         a. 取消冒泡/停止漫延:

                  1). e.stopPropagation()

                            停止  漫延

e.stopPropagation()作用是阻止目标元素的冒泡事件,但是不会阻止默认行为
阻止浏览器默认行为使用e.preventDefault();

                 2). 说明:因为e.stopPropagation()不拦自己,只拦别人,所以写前写后与自己无关!自己的代码都会执行!

                 3). 示例: 演示冒泡和阻止冒泡:

                  2_bubble.html

<!DOCTYPE HTML>
<html>
	<head>
		<title>事件处理</title>
		<meta charset="utf-8"/>
		<link rel="stylesheet" href="css/2.css"/>
		
	</head>
	<body>
		<div id="d1">
			<div id="d2">
				<div id="d3">
				</div>
			</div>
		</div>
    <script>
			var d1=document.getElementById("d1");
			var d2=document.getElementById("d2");
			var d3=document.getElementById("d3");
			//希望点哪个div,就只有哪个div喊疼!
			d1.onclick=function(){
				alert(`d1 疼!`)
			}
			d2.onclick=function(e){
				e.stopPropagation();
				alert(`d2 疼!`);
			}
			d3.onclick=function(e){
				//停止事件继续向上层冒泡
				e.stopPropagation();
				alert(`d3 疼!`);
			}
		</script>
	</body>
</html>

运行结果: 

         b. 事件委托/利用冒泡:

                  1). 问题: 如果页面中绑定太多事件监听,会导致监听队列中监听对象很多,遍历查找就会慢,就会影响事件响应的速度。

                  2). 解决: 优化: 今后,尽量减少绑定事件监听的个数

                  3). 利用冒泡/事件委托: 3步

                  a. 今后只要多个平级子元素都要绑定相同的事件处理函数时,其实只要在父元素上绑定一个处理函数,所有子元素就都可以通过冒泡机制共用父元素上的事件处理函数!

                          问题: 因为事件绑定在父元素上,所以事件处理函数中的this不再指当前点的按钮,而是指事件绑定时.前的父元素div

                  b. 今后只要利用冒泡,都要用e.target代替this获得实际点击的目标元素。

                          1). e.target 专门保存最初实际点击的那个目标元素,不随冒泡而改变。

                          2). 问题: 即使点在父元素上,也会触发父元素的事件处理函数——是我们不希望的.

                  c. 先判断当前点击的元素是不是我们想要的。只有当前点击的元素是我们想要的,才执行后续事件处理操作。

                          比如: 判断元素的标签名、className......

🔷 关于事件委托

事件委托又可以叫事件代理,事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

                  4). 示例: 使用事件委托实现计算器效果:

                  3_calc.html

<!DOCTYPE HTML>
<html>

<head>
	<title>取消与利用冒泡</title>
	<meta charset="utf-8" />
</head>

<body>
	<div id="keys">
		<button>1</button>
		<button>2</button>
		<button>3</button>
		<button>4</button><br>
		<button>C</button>
		<button>+</button>
		<button>-</button>
		<button>=</button>
	</div>
	<textarea id="sc" style="resize:none;width:200px; height:50px;" readonly></textarea>
	<script>
		//DOM 4步
		//1. 查找触发事件的元素
		//本例中: 因为多个平级的button都可以单击,所以,事件应该只绑定在他们共同的父元素上一份即可!
		var div = document.getElementById("keys")
		//2. 绑定事件处理函数
		div.onclick = function (e) {
			// alert("div 疼!");
			//点哪个按钮,让哪个按钮变小花
			//this->div
			//this.innerHTML="❀";
			//e.target代替this
			//只有当前点击的目标元素是button时,才继续执行后续操作
			if (e.target.nodeName === "BUTTON") {
				//e.target.innerHTML = "❀"
				//作业: 看注释实现完整计算器效果。
				//3. 查找要修改的元素
				//本例中:点按钮,要修改的是充当显示屏的id为sc的元素
				var sc = document.getElementById("sc");
				//4. 修改元素
				//本例中: 根据本次点的按钮不同,执行不同的操作
				//先判断点击的按钮的内容
				switch (e.target.innerHTML) {
					//如果是C,就清空显示屏文本框
					case "C":
						sc.value = "";
						break;
					//如果是=,就将文本框内容,交给eval计算结果,再将结果放回显示屏中
					case "=":
						//错误处理
						try {//尝试执行
							//eval: 可计算字符串类型的js表达式的值
							sc.value = eval(sc.value);
						} catch (err) {//如果出错
							sc.value = err;//就把错误信息显示在文本框中
						}
						break;
					//点击其余所有数字按钮和+ -号按钮,都只将按钮内容追加到文本框中算式结尾即可,不做计算
					default:
						sc.value += e.target.innerHTML;
				}
			}
		}
	</script>
</body>

</html>

运行结果: 

🌲 扩展:

◼️ 元素.nodeName:

👉 1. 专门保存一个元素的标签名

👉 2. 坑: 它保存的标签名是全大写字母的: DIV、BUTTON、INPUT...

HTML DOM nodeName 属性

nodeName 属性指定节点的节点名称。

👉 ① 如果节点是元素节点,则 nodeName 属性返回标签名。

👉 ② 如果节点是属性节点,则 nodeName 属性返回属性的名称。

👉 ③ 对于其他节点类型,nodeName 属性返回不同节点类型的不同名称。

◼️ 什么是HTML DOM

HTML DOM是HTML Document Object Model(文档对象模型)的缩写,HTML DOM则是专门适用于HTML/XHTML的文档对象模型。熟悉软件开发的人员可以将HTML DOM理解为网页的API。它将网页中的各个元素都看作一个个对象,从而使网页中的元素也可以被计算机语言获取或者编辑。例如Javascript就可以利用HTML DOM动态地修改网页。

c. 阻止默认行为:

                  1). 问题: HTML中有些元素,自身带有一些自动执行的默认的行为:

                          比如: 点击<a href="#top">,会自动在地址栏中结尾加"#top"

                          但是有些默认行为是我们不想要的

                  2). 解决: e.preventDefault();

                                        阻止   默认

                  3). 示例: 阻止a元素的默认行为:

                  4_preventDefault.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <a id="a1" href="#top">click me</a>
  <script>
    //点a时不要擅自修改地址栏结尾
    var a1=document.getElementById("a1");
    a1.onclick=function(e){
      e.preventDefault();
        //阻止  默认行为
      alert(`做我规定的事情...`);
    }
  </script>
</body>
</html>

运行结果: 

         d. 获得鼠标位置: 3组

                  1). 鼠标相对于整个屏幕左上角的距离

                          e.screenX   e.screenY

                  2). 鼠标相对于文档显示区左上角的距离(浏览器的文档显示区,浏览器属于软件即客户端)

                          e.clientX    e.clientY

                  3). 鼠标相对于当前事件所在元素左上角的距离

                          e.offsetX    e.offsetY

                  4). 示例: 点击元素获得鼠标位置:

                  5_pop1.html

<!doctype html>
<html>
 <head>
	<meta charset="UTF-8">
	<title>在当前显示区范围内实现点不到的小方块</title>
	<style>
		div{
			position:fixed;
			width:100px;
			height:100px;
			top:50px;
			left:100px;
			background-image:url(images/xiaoxin.gif);
      background-size:100%;
		}
	</style>
	
 </head>
 <body>
	<div id="pop"></div>
  <script>
		var pop=document.getElementById("pop");
		pop.onclick=function(e){
			console.log(e.screenX, e.screenY);
			console.log(e.clientX, e.clientY);
			console.log(e.offsetX, e.offsetY);
		}
	</script>
 </body>
</html>

运行结果:

❣️ 常用到的事件

◼️ onload 和 onunload 事件

  • 当用户进入后及离开页面时,会触发 onload 和 onunload 事件。
  • onload 事件可用于检测访问者的浏览器类型和浏览器版本,然后基于该信息加载网页的恰当版本。
  • onload 和 onunload 事件可用于处理 cookie。
<body onload="checkCookies()">

◼️ onchange 事件

  • onchange 事件经常与输入字段验证结合使用。
  • 下面是一个如何使用 onchange 的例子。当用户改变输入字段内容时,会调用 upperCase() 函数。
<input type="text" id="fname" onchange="upperCase()">

◼️ onmouseover 和 onmouseout 事件

  • onmouseover 和 onmouseout 事件可用于当用户将鼠标移至 HTML 元素上或移出时触发某个函数

◼️ onmousedown, onmouseup 以及 onclick 事件

  • onmousedown, onmouseup 以及 onclick 事件构成了完整的鼠标点击事件。
  • 首先当鼠标按钮被点击时,onmousedown 事件被触发;然后当鼠标按钮被释放时,onmouseup 事件被触发;最后,当鼠标点击完成后,onclick 事件被触发。

⬛ 总结: DOM 5件事: 增删改查+事件绑定 

1. 查找元素: 4种查找方式

2. 修改元素: 3种东西可修改

3. 添加/删除元素

4. HTML DOM常用对象:(了解即可)

5. DOM事件:

1. 绑定事件: js中:

(1). 一个事件只绑定一个处理函数

元素.on事件名=function(){ ... }

(2). 一个事件绑定多个处理函数

元素.addEventListener("事件名", 事件处理函数)

(3). 移除一个事件监听:

元素.removeEventListener("事件名", 原事件处理函数对象)

2. 事件模型: 捕获,目标触发,冒泡

3. 事件对象:

(1). 获得事件对象:

元素.on事件名=function(e){ ... }

(2). 阻止冒泡: e.stopPropagation()

(3). 当多个子元素都要绑定相同事件时,利用冒泡/事件委托3步:

a. 事件只在父元素上绑定一次

b. e.target代替this

c. 判断e.target的任意特征是否是我们想要的元素

(4). 阻止元素默认行为:

e.preventDefault()

(5). 获取鼠标位置:

a. 相对于屏幕左上角的x,y坐标:

e.screenX,  e.screenY

b. 相对于文档显示区左上角的x,y用坐标: 

e.clientX,  e.clientY

c. 相对于事件所在元素左上角的x,y坐标:

e.offsetX   e.offsetY

💦 DOM回顾:DOM入门基础全解析

🌲 DOM概述及DOM操作之如何查找元素_01

🌲 DOM操作之如何修改元素的内容与属性_02

🌲 DOM操作之如何修改元素的样式_03

🌲 DOM操作之如何添加、删除、替换元素_04

🌲 了解HTML DOM常用对象: 对常用元素的简化操作_05

🔘 深入浅出浏览器对象模型—BOM基础知识详解_06

​​​

如果这篇【文章】有帮助到你,希望可以给【青春木鱼】点个👍,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点,如果有对【前端技术】感兴趣的小可爱,也欢迎关注❤️❤️❤️青春木鱼❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💕💕!

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

儒雅的烤地瓜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值