一幅长文细学JavaScript(三)——DOM

文章目录

  • 3 JavaScript DOM
    • 3.1 DOM基本术语
        • DOM模型及其作用
        • 文档对象模型
        • 节点
        • 节点的属性
        • 文档对象
    • 3.2 DOM文档操作
      • 3.2.1 查找网页元素
      • 3.2.2 获取元素内容
        • 新的策略——修改样式
        • 更好的策略——修改样式
      • 3.2.3 改变元素内容
      • 3.2.4 操作网页元素
      • 3.2.5 获取元素偏移
        • offset和style的区别
      • 3.2.6 获取元素可视区
      • 3.2.7 获取元素滚动
      • 3.2.8 元素节点导航
      • 3.2.9 查找网页元素
    • 3.3 DOM文档事件
      • 3.3.1 事件入门
        • 事件基本概念
        • 事件的三要素
        • 执行事件的过程
      • 3.3.2 事件绑定
        • 事件监听版本
        • IE9之前的事件绑定
        • 事件监听发展史
      • 3.3.3 窗口事件
      • 3.3.4 鼠标事件
      • 3.3.5 键盘事件
      • 3.3.6 焦点事件
      • 3.3.7 文本事件
      • 3.3.8 表单事件
      • 3.3.9 媒体事件
      • 3.3.10 排他思想
      • 3.3.11 事件冒泡
      • 3.3.12 事件委派
      • 3.3.13 事件传播
        • 事件流
        • 事件捕获
        • 回到事件绑定
      • 3.3.14 事件对象
        • 事件对象简介
        • 事件对象常用属性和方法

3 JavaScript DOM

在前面的JS基础阶段中,我们学习的是ECMAScript标准规定的基本语法,但是只学习基本语法是无法做出网页交互效果的,为此在本章的学习中,我们要进入WebAPIs阶段。

WebAPIs是W3C组织的标准,主要学习DOM和BOM,在这一章节中,我们需要JS基本语法的铺垫,步入学习网页交互功能的道路。


3.1 DOM基本术语

DOM模型及其作用

​ 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model),它是W3C组织推荐的处理可扩展标记语言的标准编程接口,其结构为一颗DOM对象树。如果学过Python爬虫中的Xpath解析框架,你可以很好的理解我上述的话。

image-20220712223121800

​ Js可以通过DOM对HTML文档进行操作,即随心所欲操作Web界面。

  • JavaScript 能改变页面中的所有 HTML 元素
  • JavaScript 能改变页面中的所有 HTML 属性
  • JavaScript 能改变页面中的所有 CSS 样式
  • JavaScript 能删除已有的 HTML 元素和属性
  • JavaScript 能添加新的 HTML 元素和属性
  • JavaScript 能对页面中所有已有的 HTML 事件作出反应
  • JavaScript 能在页面中创建新的 HTML 事件

文档对象模型

  • 文档:一个HTML网页就是一个文档
  • 对象:网页中的每一个部分都转换为了一个对象
  • 模型:表示对象之间的关系,方便我们获取对象

节点

节点Node是构建网页最基本的组成部分。网页中的每一个部分都可看做是一个节点。节点类型多样,属性和方法也不尽相同,最常用的节点可以分为以下四类:

  • 文档节点:整个HTML文档;网页中所有的结点都是以子节点的形式存在,文档对象作为window对象的属性存在,我们不用获取可直接使用。通过该对象我们可以在整个文档访问内查找节点对象,并且可以通过该对象创建各种节点对象。
  • 元素节点:HTML文档中的HTML标签;我们可以通过多种方法访问到元素节点,如document.getElementById()。
  • 属性节点:元素的属性;通过元素节点.getAttributeNode(“属性名”)可以找到属性节点对象,但我们很少使用它。
  • 文本节点:HTML标签中的文本内容;使用元素节点.firstChild可以获取元素节点的文本节点,其一般为元素节点的第一个子节点。

节点的属性

对于每个节点来说都具备nodeName、nodeType、nodeValue三个属性。

nodeNamenodeTypenodeValue
文档节点#document9Null
元素节点标签名1Null
属性节点属性名2属性值
文本节点#text3文本内容

文档对象

  • 浏览器为我们提供了文档节点对象document,这个对象是window属性。如果你希望访问HTML页面中的任何元素,那么你必须从访问document对象开始。

  • 文档节点对象可以在页面中直接使用,文档节点代表的是整个网页


3.2 DOM文档操作

3.2.1 查找网页元素

方法说明
document.getElementById(‘id’)元素id查找元素
document.getElementByTagName(‘name’)标签名查找元素
document.getElementByClassName(‘name’)类名查找元素
document.querySelector(‘CSS选择器’)根据CSS选择器返回第一个元素
document.querySelectorAll(‘CSS选择器’)通过CSS选择器选择多个元素
document.body选择body标签的所有内容
document.documentElement选择html标签的所有内容

:JS是解释性语言,故JS代码必须写在HTML的下方,因为只有HTML生成元素了,JS才能通过DOM操纵元素。

<!DOCTYPE html>
<html lang="zh-cn">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><!-- HTML元素 --><div id = "test">测试案例1</div><p>测试案例2</p><p>测试案例3</p><div class="c1">测试案例4</div><div class = "c2">测试案例5</div><div id = "c3">测试案例6</div><div id = "c3">测试案例7</div><script>//1 通过ID找元素,注意ID大小写敏感,返回值为var test1 = document.getElementById('test');console.log(test1);console.dir(test1);//等同于log,用于查看元素结构//2 通过标签名找元素,这种方式选中所有同名标签,返回值为伪数组var test2 = document.getElementsByTagName('p');console.log(test2);//3 通过类名找元素,该方法仅支持IE9以上,返回值为伪数组var test3 = document.getElementsByClassName('c1');console.log(test3);//4 通过选择器查找第一个元素var test4 = document.querySelector('.c2');console.log(test4);//5 通过选择器选定所有元素var test5 = document.querySelectorAll('#c3');console.log(test5);var test6 = document.querySelectorAll('*');console.log(test6);//6 得到body元素var test7 = document.body;console.log(test7);//7 得到html元素var test8 = document.documentElement;console.log(test8);</script>
</body>
</html>

3.2.2 获取元素内容

:推荐学完事件再回来看

方法说明
元素节点.innerText获取HTML元素标签间的内容
元素节点.innerHTML获取HTML元素标签间内容以及标签
元素节点.属性获取HTML元素的属性值
元素节点.style.样式获取HTML元素的行内样式值
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#Test5 p{height:50px;width:100px;background: pink;}</style>
</head>
<body><!-- 测试组件 --><button>测试按钮1</button><div>测试内容1</div><br><div><button id = "testbtn2">测试按钮2</button><p id = "test2">测试内容2</p></div><br><div><button id = "testbtn3">测试按钮3——图片1</button><button id = "testbtn4">测试按钮4——图片2</button><br><img src = "./img_103.jpg" alt = "" id = "testimg" width = 300px></div><div id = "Test5"><p>测试内容5</p><br><button>测试按钮5</button></div><script>/*======innerText======*///1 获取事件源var btn1 = document.querySelector('button');var div1 = document.querySelector('div');//2 注册事件btn1.onclick = function(){div1.innerText = '测试内容已改变';}/*======innerHTML======*///1 获取事件源var btn2 = document.getElementById('testbtn2')var p2 = document.getElementById('test2');//2 注册事件btn2.onclick = function(){p2.innerHTML = '<strong>测试内容已改变</strong>';}/*======元素节点.属性======*///1 获取事件源var btn3 = document.getElementById('testbtn3');var btn4 = document.getElementById('testbtn4');var img3  = document.getElementById('testimg');//2 注册事件btn3.onclick = function(){img3.src = './img_103.jpg';}btn4.onclick = function(){img3.src = './img_112.jpg';}/*======元素节点.style.样式======*///1 获取事件源var btn5 = document.querySelector('#Test5 button');var p5 = document.querySelector('#Test5 p');//2 注册事件btn5.onclick = function(){p5.style.background = 'skyblue';}</script>
</body>
</html>

新的策略——修改样式

说明:如果要想通过DOM修改CSS样式,一个样式就要一条语句,十分难受。为此,我们可以将修改后的样式放在一个选择器中,当我们需要很多组件同时变成该样式时,使用元素.className修改该元素的所属的类,这样就可以给该元素附上提前准备好的样式。

:className方法并不是添加类,而是覆盖类。这就意味着如果元素此前拥有的类将会被覆盖。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>/*提前准备一个样式*/.Test1{color: yellowgreen;background: pink;}</style>
</head>
<body><div>测试内容1</div><button>测试按钮1</button><script>var div1 = document.querySelector('div');var btn1 = document.querySelector('button');btn1.onclick = function(){div1.className = 'Test1';}</script>
</body>
</html>

更好的策略——修改样式

说明:之前的className容易覆盖以前的类名,故我们可以使用classList方式来追加和删除类名。

方式说明
元素.classList.add(‘类名’)追加一个类
元素.classList.remove(‘类名’)删除一个类
元素.classList.toggle(‘类名’)切换一个类
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>/*提前准备一个样式*/.Test1{color: yellowgreen;background: pink;}/*样式2*/.Test2{background-color: aqua;}</style>
</head>
<body><div class = "Test1">测试内容1</div><button class = "add-btn">追加样式类</button><button class = "remove-btn">删除样式类</button><button class = "toggle-btn">切换样式类</button><script>var div = document.querySelector('div')var add_btn = document.querySelector('.add-btn')var remove_btn = document.querySelector('.remove-btn')var toggle_btn = document.querySelector('.toggle-btn')console.log(add_btn);console.log(remove_btn);add_btn.onclick = function(){div.classList.add('Test2')}remove_btn.onclick = function(){div.classList.remove('Test2');}toggle_btn.onclick = function(){div.classList.toggle('Test1');}</script>
</body>
</html>

3.2.3 改变元素内容

说明:我们可以通过以下方法修改元素的内容

方法说明
元素节点.innerText =新内容改变元素的标签值
元素节点.innerHTML = 新元素改变元素
元素节点.属性 = 新的属性值改变元素的属性值
元素节点.setAttribute(属性, 值)改变元素的属性值
元素节点.style.样式 = 新的属性值改变 HTML 元素的行内样式值

3.2.4 操作网页元素

创建 HTML 元素节点:document.createElement(element)

创建 HTML 属性节点:document.createAttribute(attribute)

创建 HTML 文本节点:document.createTextNode(text)

删除 HTML 元素:元素节点.removeChild(element)

添加 HTML 元素:元素节点.appendChild(element)

替换 HTML 元素:元素节点.replaceChild(element)

在指定的子节点前面插入新的子节点:元素节点.insertBefore(element)


3.2.5 获取元素偏移

说明:offset指偏移量,我们使用offset系列相关属性可以动态地获取该元素的位置、大小等。需要注意的是,获取的仅有数值而无单位

方法说明
元素.offsetWidth返回自身包括padding、边框、内容区的宽度,返回数值不带单位
元素.offsetHeight返回自身包括padding、边框、内容区的高度,返回数值不带单位
元素.offsetParent获取离当前元素最近的开启了定位的祖先元素
元素.offsetTop返回元素相对带有定位父元素上方的偏移
元素.offsetLeft返回元素相对带有定位父元素左边框的偏移
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>*{margin:0;padding:0;}.div{background-color: pink;height: 200px;width: 200px;border: 2px solid red;padding:2px;}</style>
</head>
<body><div class = "div"></div><script>var div = document.querySelector(".div")// offsetWidth返回自身包括padding、边框、内容区的宽度,返回数值不带单位console.log(div.offsetWidth);// offsetHeight返回自身包括padding、边框、内容区的高度,返回数值不带单位console.log(div.offsetHeight);// offsetParent获取离当前元素最近的开启了定位的祖先元素console.log(div.offsetParent);// offsetTop返回元素相对带有定位父元素上方的偏移console.log(div.offsetTop);// offsetLeft返回元素相对带有定位父元素左边框的偏移console.log(div.offsetLeft);</script>
</body>
</html>

offset和style的区别

offsetstyle
offset可以得到任意样式表中的样式值style只能得到行内样式表中的样式值
offset系列获得的数值是不带单位的style.width获得的是带有单位的字符串
offsetWidth包含padding+border+widthstyle.width获得不包含padding和border的值
offsetWidth等属性属于只读属性style.widh是可读写属性,可以获取也可以赋值

3.2.6 获取元素可视区

方法说明
元素.clientWidth返回自身包括padding、内容区宽度、不含边框,返回数值不带单位
元素.clientHeight返回自身包括padding、内容区高度、不含边框,返回数值不带单位
元素.clientTop返回元素上边框的大小
元素.cllientLeft返回元素左边框的大小
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>div{width: 200px;height: 200px;background-color: pink;border: 3px solid skyblue;margin: 0 auto;}</style>
</head>
<body><div></div><script>var div = document.querySelector('div');console.log(div.clientWidth); //200,说明不包含边框console.log(div.clientHeight);//200 说明不包含边框console.log(div.clientLeft);//3 边框的左边宽度为3console.log(div.clientTop);//3 边框的顶部宽度为3</script>
</body>
</html>

3.2.7 获取元素滚动

方法说明
元素.scrollTop返回被卷去的上侧距离,返回数值不带单位
元素.scrollLeft返回被卷去的左侧距离,返回数值不带单位
元素.scrollWidth返回自身实际的宽度,不含边框,返回数值不带单位
元素.scrollHeight返回自身实际的高度,不含边框,返回数值不带单位

image-20220723112541620

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>div{width:50px;height:100px;background-color: pink;overflow: scroll;border: 3px solid red;}</style>
</head>
<body><div>测试内容1  测试内容1  测试内容1  测试内容1  </div><script>var div = document.querySelector('div');console.log(div.scrollHeight);//208 表名内容+padding的宽度为208console.log(div.scrollTop); //0 表明没有内容在滚动条上面console.log(div.scrollWidth);//33 表名内容+padding的宽度为33console.log(div.scrollLeft);//0表名没有内容在滚动条左侧</script>
</body>
</html>

3.2.8 元素节点导航

说明:在前面的选择器中,我们通通都是使用DOM提供的方法来获取元素,但这些方法逻辑性不强且繁琐。为此,Js还提供了利用节点层级来获取元素。

方法描述
元素节点.parentNode返回元素的父节点。
元素节点.parentElement返回元素的父元素。
元素节点.childNodes返回元素的一个子节点的数组(包含空白文本Text节点)。
元素节点.children返回元素的一个子元素的集合(不包含空白文本Text节点)。但其为非标准方法
元素节点.firstChild返回元素的第一个子节点(包含空白文本Text节点)。
元素节点.firstElementChild返回元素的第一个子元素(不包含空白文本Text节点)。
元素节点.lastChild返回元素的最后一个子节点(包含空白文本Text节点)。
元素节点.lastElementChild返回元素的最后一个子元素(不包含空白文本Text节点)。
元素节点.previousSibling返回某个元素紧接之前节点(包含空白文本Text节点)。
元素节点.previousElementSibling返回指定元素的前一个兄弟元素(相同节点树层中的前一个元素节点)。
元素节点.nextSibling返回某个元素紧接之后节点(包含空白文本Text节点)。
元素节点.nextElementSibling返回指定元素的后一个兄弟元素(相同节点树层中的下一个元素节点)。
<div>我是div</div><span>我是span</span><ul><li>我是li</li><li>我是li</li><li>我是li</li></ul><div class="box"><span class = "erweima">×</span></div><script>// 1.通过已知元素节点获取最近的父节点var erweima = document.querySelector('.erweima')// var box = document.querySelector('.box') 传统写法var box = erweima.parentNode //元素导航写法console.log(box);// 2.通过已知元素节点获取所有的子节点,子节点中既有元素节点也有文本节点// 通常不建议使用该方法来获取子节点,因为太麻烦了var ul = document.querySelector('ul')console.log(ul.childNodes);// 3.非标准方法,但其获得所有浏览器认可,用于选取已知元素节点的所有子元素节点console.log(ul.children);// 4.获取第一个子节点console.log(ul.firstChild);// 5.获取第一个元素子节点console.log(ul.firstElementChild);// 6.获取最后一个子节点console.log(ul.lastChild);// 7.获取最后一个元素子节点console.log(ul.lastElementChild);</script>

3.2.9 查找网页元素

属性说明
document.anchors返回拥有 name 属性的所有<a> 元素
document.baseURI返回文档的绝对基准 URI
document.body返回 <body> 元素
document.cookie返回文档的 cookie
document.doctype返回文档的 doctype
document.documentElement返回 <html> 元素
document.documentMode返回浏览器使用的模式
document.documentURI返回文档的 URI
document.domain返回文档服务器的域名
document.forms返回所有 <form> 元素
document.embeds返回所有 <embed> 元素
document.images返回所有 <img> 元素
document.lastModified返回文档更新的日期和时间
document.title返回 <title> 元素
document.scripts返回所有 <script> 元素

3.3 DOM文档事件

3.3.1 事件入门

事件基本概念

事件:编程时系统内发生的动作或者发生的事情

事件监听:让程序检测是否有事件发生,一旦有事件触发,就立即调用一个函数做出响应,也称为注册事件。


事件的三要素

  • 事件源:事件被触发的对象
  • 事件类型:如何触发
  • 事件调用的函数:要做什么事

执行事件的过程

  1. 获取事件源
  2. 注册事件(绑定事件)
  3. 添加事件处理程序

3.3.2 事件绑定

事件监听版本

版本写法
DOM L0事件源.on事件 = function(){}
DOM L2事件源.addEventListener(事件,事件处理函数,布尔值)

  • L0和L2有很大区别,我们会在后面讨论。
  • 第三个参数时布尔值,指定使用事件冒泡还是事件捕获,如果是true则为捕获,如果是false则为传播,此参数可省略。
  • 在IE9之前不支持L2,可使用attachEvent()代替。

IE9之前的事件绑定

格式:事件源.attachEvent(事件,事件处理函数)

说明:官方在文档中明确指出,在实际开发中不要使用该方式


事件监听发展史

  • DMO L0:是DOM发展的第一个版本
  • DOM L1:1998.10.1称为W3C推荐标准
  • DOM L2:使用addEventListener注册事件
  • DOM L3:DOM3级别事件模块在DOM2级事件的基础上重新定义了这些事件,也添加了一些新事件类型
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><button id = "btn1">测试按钮1</button><button id = "btn2">测试按钮2</button><script>/*老版写法*/var btn1 = document.getElementById("btn1");btn1.onclick = function(){alert('按钮1已被点击');}/*新版写法*/var btn2 = document.getElementById("btn2");btn2.addEventListener("click", function(){alert('按钮2已被点击');})</script>
</body>
</html>

3.3.3 窗口事件

:在下面各类型事件的使用中,我们不推荐一个一个全部死记,要用什么查什么即可。

属性描述
onblur当窗口失去焦点时运行脚本。
onfocus当窗口获得焦点时运行脚本。
onload当文档加载之后运行脚本。
onresize当调整窗口大小时运行脚本。常用作响应式布局。
onstorage当 Web Storage 区域更新时(存储空间中的数据发生变化时)运行脚本。
DOMContentLoaded不包括样式表、图片、flash等,仅当DOM加载完成即触发时间,适合用于页面图片较多的情况

3.3.4 鼠标事件

属性描述
onclick当单击鼠标时运行脚本。
ondblclick当双击鼠标时运行脚本。
onmousedown当按下鼠标按钮时运行脚本。
onmouseup当松开鼠标按钮时运行脚本。
onmousemove当鼠标指针移动时运行脚本。
onmouseover当鼠标指针移至元素之上时运行脚本,不可以阻止冒泡。
onmouseout当鼠标指针移出元素时运行脚本,不可以阻止冒泡。
onmouseenter当鼠标指针移至元素之上时运行脚本,可以阻止冒泡。
onmouseleave当鼠标指针移出元素时运行脚本,可以阻止冒泡。
onmousewheel当转动鼠标滚轮时运行脚本。
onscroll当滚动元素的滚动条时运行脚本。

3.3.5 键盘事件

属性描述
onkeydown当按下按键时运行脚本。
onkeyup当松开按键时运行脚本。
onkeypress当按下并松开按键时运行脚本。

3.3.6 焦点事件

属性描述
focus获得焦点
blur失去焦点

3.3.7 文本事件

属性描述
input用户输入文本时开始运行脚本

3.3.8 表单事件

属性描述
onblur当元素失去焦点时运行脚本。
onfocus当元素获得焦点时运行脚本。
onchange当元素改变时运行脚本。
oninput当元素获得用户输入时运行脚本。
oninvalid当元素无效时运行脚本。
onselect当选取元素时运行脚本。
onsubmit当提交表单时运行脚本。

3.3.9 媒体事件

属性描述
onabort当发生中止事件时运行脚本。
oncanplay当媒介能够开始播放但可能因缓冲而需要停止时运行脚本。
oncanplaythrough当媒介能够无需因缓冲而停止即可播放至结尾时运行脚本。
ondurationchange当媒介长度改变时运行脚本。
onemptied当媒介资源元素突然为空时(网络错误、加载错误等)运行脚本。
onended当媒介已抵达结尾时运行脚本。
onerror当在元素加载期间发生错误时运行脚本。
onloadeddata当加载媒介数据时运行脚本。
onloadedmetadata当媒介元素的持续时间以及其它媒介数据已加载时运行脚本。
onloadstart当浏览器开始加载媒介数据时运行脚本。
onpause当媒介数据暂停时运行脚本。
onplay当媒介数据将要开始播放时运行脚本。
onplaying当媒介数据已开始播放时运行脚本。
onprogress当浏览器正在取媒介数据时运行脚本。
onratechange当媒介数据的播放速率改变时运行脚本。
onreadystatechange当就绪状态(ready-state)改变时运行脚本。
onseeked当媒介元素的定位属性不再为真且定位已结束时运行脚本。
onseeking当媒介元素的定位属性为真且定位已开始时运行脚本。
onstalled当取回媒介数据过程中(延迟)存在错误时运行脚本。
onsuspend当浏览器已在取媒介数据但在取回整个媒介文件之前停止时运行脚本。
ontimeupdate当媒介改变其播放位置时运行脚本。
onvolumechange当媒介改变音量亦或当音量被设置为静音时运行脚本。
onwaiting当媒介已停止播放但打算继续播放时运行脚本。

3.3.10 排他思想

排他思想:当前元素为A状态,其他为B状态

应用:轮播图等

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.pink{background-color: pink;}</style>
</head>
<body><button class = 'pink'>测试按钮1</button><button>测试按钮2</button><button>测试按钮3</button><script>var btns = document.querySelectorAll('button');for (var i = 0; i < btns.length; i++) {btns[i].addEventListener('click',function(){document.querySelector('.pink').classList.remove('pink');this.classList.add('pink');})}</script>
</body>
</html>

3.3.11 事件冒泡

事件冒泡:事件的向上传导。当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>div{background: skyblue;width: 300px;height: 300px;}div  div{background: pink;height: 50px;width:50px;}</style>
</head>
<body><div><div></div></div><script>var innerDiv = document.querySelector('div > div');var outerDiv = document.querySelector('div');innerDiv.onclick = function(){alert("您点击了内层");}outerDiv.onclick = function(){alert("您点击了外层");}</script>
</body>
</html>

3.3.12 事件委派

事件委派:为多个元素绑定同一个事件。

事件委派原理:利用事件冒泡。将事件统一绑定给祖先元素后,点击后代元素,则后代元素会冒泡到祖先元素上去寻找事件。

事件委派的好处:通过委派可以减少事件绑定的次数,提高程序的性能。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>p{background-color: greenyellow;}</style>
</head>
<body><div class = "divClass"><p>测试内容1</p><p>测试内容2</p><p>测试内容3</p></div><script>var div1 = document.querySelector('div');/*target属性用于返回一个事件触发对象*/div1.onclick = function(event){if(event.target.className != 'divClass'){alert('测试内容已被点击');}}</script>
</body>
</html>

3.3.13 事件传播

事件流

说明:事件流描述的是从页面中接收事件的顺序。事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。如我们给一个div注册点击事件:

image-20220815234456616

这时候我们需要先去寻找这个元素,这个过程我们称为捕获阶段,找到当前目标后,进入当前目标阶段,对目标进行事件的执行,最后进入冒泡阶段,div元素执行事件后,父级元素如果有相同类型的事件,则也会触发,如两者都具有点击事件。

事件捕获

在HTML DOM中有两种事件传播方式:冒泡捕获。我们在前面已经谈论过冒泡,冒泡就是从内而外发生事件,而捕获则和冒泡反着来。


回到事件绑定

方法说明
事件源.addEventListener(事件,事件处理函数,布尔值)绑定事件
事件源.removeEventListener(事件,事件处理函数)解绑事件

  • L2绑定事件允许向相同元素添加多个不同类型的事件,且不覆盖
  • L2绑定和解绑只支持IE8之后的版本

3.3.14 事件对象

事件对象简介

说明:只要绑定了事件,则系统会自动创建一个事件对象event,可简写为e或evt。我们将其写于事件回调函数的参数列表中。


事件对象常用属性和方法

事件对象属性方法说明
e.target返回触发事件的对象
e.srcElement返回触发事件的对象 ie6-8才可使用
e.type返回事件的类型
e.cancelBubble阻止事件冒泡 ie6-8使用
e.returnValue阻止默认事件发生 ie6-8使用
e.preventDefault()阻止默认事件发生
e.stopPropagation()阻止事件冒泡

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/398453.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2016国内移动广告平台排行榜

为什么80%的码农都做不了架构师&#xff1f;>>> 移动营销的发展可追溯至第一台便携式手机的诞生&#xff0c;并随着移动终端的更新迭代和广告技术的发展创新&#xff1b;随着移动互联网的技术与商业模式的迅速发展&#xff0c;移动营销领域面临着种种创新与改革&am…

Planning Strategy 和Requirement type的思考

Planning Strategy 和 requirement type的联系 1. 当需要对一个material进行计划的时候 &#xff0c;我们会自然的考虑到plant的 production方式 ( MTO production or MTS production) ,如果能确定下来是MTO 还是MTS 的方式 &#xff0c; 那就可以确定了计划策略的选择 。 而计…

【摄影】田子坊

图片发自简书App图片发自简书App图片发自简书App图片发自简书App图片发自简书App图片发自简书App图片发自简书App图片发自简书App转载于:https://www.cnblogs.com/wangting888/p/9701627.html

selenium RC 环境配置

在网上搜索了许久&#xff0c;没找到有具体的配置&#xff0c;只是简单了写了几个步骤&#xff0c;自己琢磨了一下&#xff0c;于是&#xff0c;就想整理一篇文章&#xff0c;便于以后温习。 本文是参照官网的步骤进行了&#xff0c;当然了&#xff0c;也不完成相同。在这里我要…

一幅长文细学GaussDB(二)——数据库基础知识

文章目录2 数据库基础知识2.1 数据库管理简介数据库管理数据库管理工作范围对象管理制定数据库对象命名规范备份和恢复灾难恢复备份方式数据库安装数据库卸载数据库迁移数据库扩容例行维护工作2.2 数据库重要概念数据库和数据库实例数据库连接和会话数据库连接池模式表空间表数…

hive如何处理not in和in的问题

2019独角兽企业重金招聘Python工程师标准>>> 首先我们先创建两个表和测试数据。建表语句如下&#xff1a; create table table1(uid STRING, dayTimes BIGINT) PARTITIONED BY (dt STRING); create table table2(uid STRING, monTimes BIGINT) PARTITIONED BY (dt S…

一幅长文细学GaussDB(三)——SQL语法

文章目录3 SQL语法3.1 SQL语句概述SQL语句介绍SQL语句分类3.2 数据类型常用数据类型非常用数据类型3.3 系统函数概述数值计算函数字符处理函数时间日期函数类型转换函数系统信息函数3.4 操作符概述逻辑操作符比较操作符算术操作符测试操作符其他操作符3 SQL语法 华为GaussDB(f…

从网络获取数据显示到TableViewCell容易犯的错

2019独角兽企业重金招聘Python工程师标准>>> 昨晚第一次做用网络接口获取的数据&#xff0c;显示到自己的cell上&#xff0c;犯了很多的错&#xff0c; 总结如下&#xff1b; 1.数据源数组必须首先初始化&#xff0c;一般使用的是懒加载&#xff1b; 2.异步获取网络…

第二学期-第一次作业

1-1. 计算两数的和与差 1.设计思路 第一步&#xff1a;设出被调用函数 op1, op2, *psum, *pdiff &#xff0c;利用被调函数计算*psum的值和*pdiff的值&#xff1b; 第二步&#xff1a;代入到主函数就是计算a、b的和与差&#xff1b; 第三部&#xff1a;对所得到数值进行输出&a…

一幅长文细学华为MRS大数据开发(三)——Hive

文章目录3 HIVE3.1 Hive概述Hive简介Hive应用场景Hive与传统数据仓库比较Hive优点3.2 Hive功能及架构Hive运行流程Hive数据存储模型Hive数据存储模型-分区和分桶Hive数据存储模型-托管表和外部表Hive支持的函数3.3 Hive基本操作Hive使用DDL操作DML操作DQL操作3 HIVE Apache Hi…

Huffman树进行编码和译码

//编码 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<queue> #include<fstream> #include<map> using namespace std;typedef struct HuffmanNode{int w;//节点…

一幅长文细学JavaScript(五)——ES6-ES11新特性

5 ES版本 摘要 ES5的先天不足致使ES后续版本的发展&#xff0c;这也是前端人员绕不开的一个点。如果我们想要在工作和面试中轻松解决问题&#xff0c;那么了解ES6-ES11是必不可少的。 在本文中&#xff0c;我将采用一种更加通俗的方式来讲述这一块知识点&#xff0c;而不是照搬…

一幅长文细学Vue(一)——Webpack打包工具

1 项目开发工具 摘要 ​ 在本文中&#xff0c;我们会详细讨论webpack是如何打包发布项目&#xff0c;不过对于Vue来说&#xff0c;Vite可以做到和webpack一样的功能。 声明&#xff1a;如果想要看懂此文章&#xff0c;需具备node.js中npm的知识。 作者&#xff1a;来自ArimaMis…

I00005 打印直角三角形字符图案

曾经的计算机&#xff0c;没有显示屏&#xff0c;人们操作计算机时&#xff0c;用打印机记录执行的操作命令。 后来有了显示屏&#xff0c;不过最初的显示屏是字符频幕&#xff0c;输出只能是字符。 即使是今日&#xff0c;计算机已经进入多窗口图形界面时代&#xff0c;有时程…

动态数组使用

1 #include<stdio.h>2 #include<stdlib.h>3 4 int main()5 {6 int i;7 int n; //用于记录输入的整数的个数 8 int *p; //用于指向动态数组的存储空间 9 int sum0,average; //用于记录输入的整数的和与平均值 10 11 scanf("%d"…

Linux下安装Redis及搭建主从

Linux下安装Redis 首先在官网下载对应版本的redis包&#xff0c;这里本人使用的是redis-4.0.8.tar.gz。然后在服务器中存放redis包的路径下执行tar –vxf redis-4.0.8.tar.gz&#xff08;这里对应下载的包&#xff09;&#xff0c;解压redis后,cd 进入 redis-4.0.8&#xff08;…

图解安装CentOS 6.6

以下是在虚拟机上安装CentOS 6.6的过程。一、安装文件:CentOS-6.6-x86_64-bin-DVD.iso二、安装步骤# 虚拟机的配置这里省略&#xff0c;在百度上有很多帖子可以参考。开启虚拟机进入安装界面&#xff0c;如下图所示选择第一个选项&#xff0c;按Enter安装程序加载完后&#xff…

一幅长文细学Vue(三)——组件基础(上)

3 组件基础&#xff08;上&#xff09; 摘要 ​ 在本文中&#xff0c;我们将学习什么是SPA&#xff0c;以及Vue中组件的基本使用。 声明&#xff1a;为了文章的清爽性&#xff0c;在文章内部的代码演示中只会附上部分演示代码&#xff0c;main.js文件的代码通常不贴出&#xff…

综合练习:词频统计

下载一首英文的歌词或文章 将所有,.&#xff1f;&#xff01;’:等分隔符全部替换为空格 将所有大写转换为小写 生成单词列表 fopen(news.txt,r) newsf.read() f.close() sep,.!"?: for c in sep:newsnews.replace(c, )wordListnews.lower().split()for w in wordList:pr…

linux中fcntl()、lockf、flock的区别

fcntl()、lockf、flock的区别 ——lvyilong316 这三个函数的作用都是给文件加锁&#xff0c;那它们有什么区别呢&#xff1f;首先flock和fcntl是系统调用&#xff0c;而lockf是库函数。lockf实际上是fcntl的封装&#xff0c;所以lockf和fcntl的底层实现是一样的&#xff0c;对文…