JS笔记(3/8)之DOM,事件

本文详细介绍了DOM的概念及其在JavaScript中的应用,包括DOM节点类型、节点关系操作、Node接口、NodeList和HTMLCollection接口。此外,还探讨了事件处理,如EventTarget接口、事件模型、事件对象以及常见的鼠标事件和键盘事件。DOM操作与事件模型是JS操控网页的基础,通过这些接口和事件,开发者可以实现丰富的交互效果。
摘要由CSDN通过智能技术生成

DOM

DOM概述

DOM(Document Object Model), 全称为"文档对象模型".它的作用是将网页转为一个JS对象,从而可以用脚本进行各种操作(比如增删内容)。

浏览器会根据DOM模型,将结构化文档(比如xml,html)解析成一系列的节点,再由这些节点组成一个树状结构(DOM tree). 所有的节点以及最顶层的树状节点,都有规范的对外接口。

通过这些接口,就可以对任一个节点进行操作,也就是DOM操作。

严格来说,DOM其实是一个接口规范,可以用任何语言实现。所以DOM不是JS语法的一部分,但DOM操作是JS最常见的任务,没有DOM,js就无法控制网页。另一方面,JS也是最常用于DOM操作的语言。

DOM节点类型

DOM最小组成单位叫做节点(node)

节点类型7种
文档节点Document:整个文档树的顶层节点
文档类型节点DocumentType:doctype标签(比如<!DOCTYPE html>)
元素节点Element:网页的各种HTML标签(比如<body><a>等)
元素属性节点Attr:网页元素的属性(比如class="right")
Text:标签之间或标签包含的文本
Comment:注释
文档片段节点DocumentFragment:文档的片段??

浏览器提供一个原生的节点对象Node,上面这七种节点都继承了Node,因此具有一些共同的属性和方法。

节点树

DOM 树有一个顶层节点,下一层都是顶层节点的子节点,

浏览器原生提供document节点,代表整个文档。

文档的第一层有两个节点,第一个是文档类型节点(<!doctype html>),第二个是 HTML 网页的顶层容器标签。

后者构成了树结构的根节点(root node),其他 HTML 标签节点都是它的下级节点。

除了根节点,其他节点都有三种层级关系。

父节点关系(parentNode):直接的那个上级节点
子节点关系(childNodes):直接的下级节点
同级节点关系(sibling):拥有同一个父节点的节点

DOM 提供操作接口,用来获取这三种关系的节点。比如,子节点接口包括firstChild(第一个子节点)和lastChild(最后一个子节点)等属性,同级节点接口包括nextSibling(紧邻在后的那个同级节点)和previousSibling(紧邻在前的那个同级节点)属性。

Node接口

属性
Node.prototype.nodeType
Node.prototype.nodeName
Node.prototype.nodeValue
Node.prototype.textContent
Node.prototype.baseURI
Node.prototype.ownerDocument
Node.prototype.nextSibling
Node.prototype.previousSibling
Node.prototype.parentNode
Node.prototype.parentElement
Node.prototype.firstChild,Node.prototype.lastChild
Node.prototype.childNodes
Node.prototype.isConnected
方法
Node.prototype.appendChild()
Node.prototype.hasChildNodes()
Node.prototype.cloneNode()
Node.prototype.insertBefore()
Node.prototype.removeChild()
Node.prototype.replaceChild()
Node.prototype.contains()
Node.prototype.compareDocumentPosition()
Node.prototype.isEqualNode(),Node.prototype.isSameNode()
Node.prototype.normalize()
Node.prototype.getRootNode()

NodeList 接口; HTMLCollection 接口

DOM 提供两种节点集合,用于容纳多个节点:NodeList和HTMLCollection。

主要区别是,NodeList可以包含各种类型的节点,HTMLCollection只能包含 HTML 元素节点。
NodeList 接口
NodeList实例是一个类似数组的对象,它的成员是节点对象。通过以下方法可以得到NodeList实例。

Node.childNodes
document.querySelectorAll()等节点搜索方法

NodeList.prototype.length
length属性返回 NodeList 实例包含的节点数量

NodeList.prototype.forEach()
forEach方法用于遍历 NodeList 的所有成员。它接受一个回调函数作为参数,每一轮遍历就执行一次这个回调函数,用法与数组实例的forEach方法完全一致。

NodeList.prototype.item()
item方法接受一个整数值作为参数,表示成员的位置,返回该位置上的成员。

NodeList.prototype.keys(),NodeList.prototype.values(),NodeList.prototype.entries()
这三个方法都返回一个 ES6 的遍历器对象,可以通过for…of循环遍历获取每一个成员的信息。区别在于,keys()返回键名的遍历器,values()返回键值的遍历器,entries()返回的遍历器同时包含键名和键值的信息。

HTMLCollection 接口
HTMLCollection是一个节点对象的集合,只能包含元素节点(element),不能包含其他类型的节点。它的返回值是一个类似数组的对象,但是与NodeList接口不同,HTMLCollection没有forEach方法,只能使用for循环遍历。

HTMLCollection.prototype.length
length属性返回HTMLCollection实例包含的成员数量。

HTMLCollection.prototype.item()
item方法接受一个整数值作为参数,表示成员的位置,返回该位置上的成员。

HTMLCollection.prototype.namedItem()
namedItem方法的参数是一个字符串,表示id属性或name属性的值,返回对应的元素节点。如果没有对应的节点,则返回null。

ParentNode 接口,ChildNode 接口

节点对象除了继承 Node 接口以外,还拥有其他接口。ParentNode接口表示当前节点是一个父节点,提供一些处理子节点的方法。ChildNode接口表示当前节点是一个子节点,提供一些相关方法。

ParentNode 接口
如果当前节点是父节点,就会混入(mixin)ParentNode接口。节点类型中,元素节点,文档节点,文档片段节点拥有子节点,因此只有这三类节点拥有ParentNode接口。

四个属性,两个方法
ParentNode.children
ParentNode.firstElementChild
ParentNode.lastElementChild
ParentNode.childElementCount
ParentNode.append(),ParentNode.prepend()

ChildNode 接口

如果一个节点有父节点,那么该节点就拥有了ChildNode接口。

四个方法
ChildNode.remove()
ChildNode.before(),ChildNode.after()
ChildNode.replaceWith()

Document 节点

document节点对象代表整个文档,每张网页都有自己的document对象。
Document节点

Element 节点

Element节点对象对应网页的 HTML 元素。每一个 HTML 元素,在 DOM 树上都会转化成一个Element节点对象(以下简称元素节点)。
Element节点

元素属性操作

HTML 元素包括标签名和若干个键值对,这个键值对就称为“属性”(attribute)。这个属性本身就是一个对象(Attr对象),但实际很少使用。一般是通过元素节点对象(Element对象)来操作属性。本章介绍如何操作这些属性。

Element.attributes 属性
每个元素对象有一个attributes属性,使用可以返回一个类似数组的动态对象,数组的成员是该元素标签的所有属性节点对象,

如何引用该元素对象的属性:

// HTML 代码如下
// <body bgcolor="yellow" οnlοad="">
document.body.attributes[0]
document.body.attributes.bgcolor
document.body.attributes['ONLOAD']

每个元素的属性(对象),还有有name 和 value 两个属性,对应该属性的属性名和属性值,等同于nodeName属性和nodeValue属性。

// HTML代码为
// <div id="mydiv">
var n = document.getElementById('mydiv');

n.attributes[0].name // "id"
n.attributes[0].nodeName // "id"

n.attributes[0].value // "mydiv"
n.attributes[0].nodeValue // "mydiv"

遍历一个元素节点的所有属性:

var para = document.getElementsByTagName('p')[0];
var result = document.getElementById('result');

if (para.hasAttributes()) {
  var attrs = para.attributes;
  var output = '';
  for(var i = attrs.length - 1; i >= 0; i--) {
    output += attrs[i].name + '->' + attrs[i].value;
  }
  result.textContent = output;
} else {
  result.textContent = 'No attributes to show';
}

元素的标准属性
其实就是标准规定各个标签默认具有属性,这些属性会自动称为元素节点对象的属性。
添加表单的属性时,常用这些知识:例如:

var f = document.forms[0];
f.action = 'submit.php';
f.method = 'POST';
//为表单添加提交网址和提交方法。

注意:这种用法,无法删除属性

HTML属性名大小写不敏感,但是JS对象的属性名是敏感的;所以在JS中使用HTML元素属性名时,一律采用小写,如果包含多个单词采用骆驼拼写法。

有些HTML属性名是JS的保留字,转为JS属性时,必须改名。主要有两个

for属性改为htmlFor
class属性改为className

另外,HTML 属性值一般都是字符串,但是 JavaScript 属性会自动转换类型。比如,将字符串true转为布尔值,将onClick的值转为一个函数,将style属性的值转为一个CSSStyleDeclaration对象。因此,可以对这些属性赋予各种类型的值。???

属性操作的标准方法
Element.getAttribute()
Element.getAttribute方法返回当前元素节点的指定属性的属性值。如果指定属性不存在,则返回null。

Element.getAttributeNames()
Element.getAttributeNames()返回一个数组,成员是当前元素的所有属性的名字。如果当前元素没有任何属性,则返回一个空数组。使用Element.attributes属性,也可以拿到同样的结果,唯一的区别是它返回的是类似数组的对象。

Element.setAttribute()
Element.setAttribute方法用于为当前元素节点新增属性。如果同名属性已存在,则相当于编辑已存在的属性。该方法没有返回值。

// HTML 代码为
// <button>Hello World</button>
var b = document.querySelector('button');
b.setAttribute('name', 'myButton');
b.setAttribute('disabled', true);

上面代码中,button元素的name属性被设成myButton,disabled属性被设成true。

Element.hasAttribute()
Element.hasAttribute方法返回一个布尔值,表示当前元素节点是否包含指定属性。

Element.hasAttributes()
Element.hasAttributes方法返回一个布尔值,表示当前元素是否有属性,如果没有任何属性,就返回false,否则返回true。

Element.removeAttribute()
Element.removeAttribute方法移除指定属性。该方法没有返回值。

自定义属性,例如使用标准提供的data- 属性。*
直接给html元素定义新的属性,虽然可以使用getAttribute()和setAttribute()读写这个属性,但是因为属性不符合标准,网页代码无法通过校验。

所以使用标准提供的data-*属性。

<div id="mydiv" data-foo="bar">

然后,使用元素节点对象的dataset属性,它指向一个对象,可以用来操作 HTML 元素标签的data-*属性。

var n = document.getElementById('mydiv');
n.dataset.foo // bar
n.dataset.foo = 'baz'

上面代码中,通过dataset.foo读写data-foo属性。
删除一个data-*属性,可以直接使用delete命令。

delete document.getElementById('myDiv').dataset.foo;

除了dataset属性,也可以用getAttribute(‘data-foo’)、removeAttribute(‘data-foo’)、setAttribute(‘data-foo’)、hasAttribute(‘data-foo’)等方法操作data-*属性。

注意,data-后面的属性名有限制,只能包含字母、数字、连词线(-)、点(.)、冒号(:)和下划线(_)。而且,属性名不应该使用A到Z的大写字母,比如不能有data-helloWorld这样的属性名,而要写成data-hello-world。

转成dataset的键名时,连词线后面如果跟着一个小写字母,那么连词线会被移除,该小写字母转为大写字母,其他字符不变。反过来,dataset的键名转成属性名时,所有大写字母都会被转成连词线+该字母的小写形式,其他字符不变。比如,dataset.helloWorld会转成data-hello-world。??

Text 节点

Text 节点的概念
文本节点(Text)代表元素节点(Element)和属性节点(Attribute)的文本内容。如果一个节点只包含一段文本,那么它就有一个文本子节点,代表该节点的文本内容。

通常我们使用父节点的firstChild、nextSibling等属性获取文本节点,或者使用Document节点的createTextNode方法创造一个文本节点。

待补充

DocumentFragment 节点

待补充

事件

事件的本质,本身是各个组成部分之间的一种通信方式,也是异步编程的一种实现???,DOM支持大量的事件。

EventTarget 接口

DOM的事件操作(监听和触发),都定义在EventTarget接口。所有节点对象都部署了这个接口,其他一些需要事件通信的浏览器内置对象(比如,XMLHttpRequest、AudioNode、AudioContext)也部署了这个接口。

该接口主要提供三个实例方法

addEventListener:绑定事件的监听函数
removeEventListener:移除事件的监听函数
dispatchEvent:触发事件

事件模型

浏览器的事件模型,就是通过监听函数(listener)对事件做出反应。事件发生后,浏览器监听到了这个事件,就会执行对应的监听函数。这是事件驱动编程模式(event-driven)的主要编程方式。

JS有三种方法,可以为事件绑定监听函数

HTML 的 on- 属性
元素节点的事件属性
EventTarget.addEventListener()

第一种“HTML 的 on- 属性”,违反了 HTML 与 JavaScript 代码相分离的原则,将两者写在一起,不利于代码分工,因此不推荐使用。
第二种“元素节点的事件属性”的缺点在于,同一个事件只能定义一个监听函数,也就是说,如果定义两次onclick属性,后一次定义会覆盖前一次。因此,也不推荐使用。
第三种EventTarget.addEventListener是推荐的指定监听函数的方法。它有如下优点:

同一个事件可以添加多个监听函数。
能够指定在哪个阶段(捕获阶段还是冒泡阶段)触发监听函数。
除了 DOM 节点,其他对象(比如window、XMLHttpRequest等)也有这个接口,它等于是整个 JavaScript 统一的监听函数接口。

this的指向
监听函数内部的this指向触发事件的那个元素节点。

事件的传播
很重要

事件的代理
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)

待补充

Event对象

事件发生以后,会产生一个事件对象,作为参数传给监听函数。浏览器原生提供一个Event对象,所有的事件都是这个对象的实例,或者说继承了Event.prototype对象。

Event对象本身就是一个构造函数,可以用来生成新的实例。

event = new Event(type, options);

Event构造函数接受两个参数。第一个参数type是字符串,表示事件的名称;第二个参数options是一个对象,表示事件对象的配置。该对象主要有下面两个属性。

bubbles:布尔值,可选,默认为false,表示事件对象是否冒泡。
cancelable:布尔值,可选,默认为false,表示事件是否可以被取消,即能否用Event.preventDefault()取消这个事件。一旦事件被取消,就好像从来没有发生过,不会触发浏览器对该事件的默认行为。

鼠标事件

鼠标事件指与鼠标相关的事件,继承了MouseEvent接口。具体的事件主要有以下一些。

鼠标事件的种类
click:按下鼠标(通常是按下主按钮)时触发。
dblclick:在同一个元素上双击鼠标时触发。
mousedown:按下鼠标键时触发。
mouseup:释放按下的鼠标键时触发。
mousemove:当鼠标在一个节点内部移动时触发。当鼠标持续移动时,该事件会连续触发。为了避免性能问题,建议对该事件的监听函数做一些限定,比如限定一段时间内只能运行一次。
mouseenter:鼠标进入一个节点时触发,进入子节点不会触发这个事件(详见后文)。
mouseover:鼠标进入一个节点时触发,进入子节点会再一次触发这个事件(详见后文)。
mouseout:鼠标离开一个节点时触发,离开父节点也会触发这个事件(详见后文)。
mouseleave:鼠标离开一个节点时触发,离开父节点不会触发这个事件(详见后文)。
contextmenu:按下鼠标右键时(上下文菜单出现前)触发,或者按下“上下文菜单键”时触发。
wheel:滚动鼠标的滚轮时触发,该事件继承的是WheelEvent接口。

MouseEvent 接口概述
MouseEvent接口代表了鼠标相关的事件,单击(click)、双击(dblclick)、松开鼠标键(mouseup)、按下鼠标键(mousedown)等动作,所产生的事件对象都是MouseEvent实例。此外,滚轮事件和拖拉事件也是MouseEvent实例。

MouseEvent接口继承了Event接口,所以拥有Event的所有属性和方法。它还有自己的属性和方法。

MouseEvent 接口的实例属性
MouseEvent.altKey,MouseEvent.ctrlKey,MouseEvent.metaKey,MouseEvent.shiftKey
MouseEvent.button,MouseEvent.buttons
MouseEvent.clientX,MouseEvent.clientY
MouseEvent.movementX,MouseEvent.movementY
MouseEvent.screenX,MouseEvent.screenY
MouseEvent.offsetX,MouseEvent.offsetY
MouseEvent.pageX,MouseEvent.pageY
MouseEvent.relatedTarget

MouseEvent 接口的实例方法
MouseEvent.getModifierState()
该方法返回一个布尔值,表示用户是否按下了大写键,他的参数是一个表示功能键的字符串
例如:

document.addEventListener('click', function (e) {
  console.log(e.getModifierState('CapsLock'));
}, false);

WheelEvent 接口
WheelEvent 接口继承了 MouseEvent 实例,代表鼠标滚轮事件的实例对象。目前,鼠标滚轮相关的事件只有一个wheel事件,用户滚动鼠标的滚轮,就生成这个事件的实例。

浏览器原生提供WheelEvent()构造函数,用来生成WheelEvent实例。
WheelEvent()构造函数可以接受两个参数,第一个是字符串,表示事件类型,对于滚轮事件来说,这个值目前只能是wheel。第二个参数是事件的配置对象。该对象的属性除了Event、UIEvent的配置属性以外,还可以接受以下几个属性,所有属性都是可选的。

deltaX:数值,表示滚轮的水平滚动量,默认值是 0.0。
deltaY:数值,表示滚轮的垂直滚动量,默认值是 0.0。
deltaZ:数值,表示滚轮的 Z 轴滚动量,默认值是 0.0。
deltaMode:数值,表示相关的滚动事件的单位,适用于上面三个属性。0表示滚动单位为像素,1表示单位为行,2表示单位为页,默认为0。

WheelEvent事件实例除了具有Event和MouseEvent的实例属性和实例方法,还有一些自己的实例属性,但是没有自己的实例方法。

WheelEvent.deltaX:数值,表示滚轮的水平滚动量。 WheelEvent.deltaY:数值,表示滚轮的垂直滚动量。
WheelEvent.deltaZ:数值,表示滚轮的 Z 轴滚动量。
WheelEvent.deltaMode:数值,表示上面三个属性的单位,0是像素,1是行,2是页。

键盘事件

进度事件

表单事件

触摸事件

拖拉事件

其他常见事件

GlobalEventHandle接口

浏览器模型

JS是浏览器内置的脚本语言,浏览器内置了JS引擎,并提供各种接口,以使JS脚本可以控制浏览器的各种功能。一旦网页内嵌了JS脚本,浏览器就会执行脚本,从而达到操作浏览器的目的,实现网页的各种动态效果。

本章介绍浏览器提供的各种JS接口

浏览器模型概述

代码嵌入网页的方法

<script>元素直接嵌入代码。
<script>标签加载外部脚本
事件属性
URL 协议

script元素内部直接嵌入代码:
该标签有一个type属性,用来指定脚本类型。其包含两个属性值

text/javascript:这是默认值,也是历史上一贯设定的值。如果你省略type属性,默认就是这个值。对于老式浏览器,设为这个值比较好。
application/javascript:对于较新的浏览器,建议设为这个值。

由于默认就是JS代码,所以type属性可以省略。

script标签指定加载外部的js脚本文件

<script src="https://www.example.com/script.js"></script>
<script charset="utf-8" src="https://www.example.com/script.js"></script>
//如果脚本文件中使用了非英语字符,还应该在script标签中注明字符的编码
//由于已经指定了JS脚本文件,那么script标签之间的代码就会自动被无视
//该js文件,不应该有heml代码和再出现<script>标签

为了防止攻击者篡改外部脚本,script标签允许设置一个integrity属性,写入该外部脚本的 Hash 签名,用来验证脚本的一致性。

<script src="/assets/application.js"
  integrity="sha256-TvVUHzSfftWg1rcfL6TIJ0XKEGrgLyEq6lEpcmrG9qs=">
</script>

上面代码中,script标签有一个integrity属性,指定了外部脚本/assets/application.js的 SHA256 签名。一旦有人改了这个脚本,导致 SHA256 签名不匹配,浏览器就会拒绝加载。

事件属性
网页元素的事件属性(比如onclick和onmouseover),可以写入 JavaScript 代码。当指定事件发生时,就会调用这些代码。例如:

<button id="myBtn" onclick="console.log(this.id)">点击</button>

上述代码只有一条JS语句,onclick
如果有多个语句,使用分号分割即可。

URL协议
URL 支持javascript:协议,即在 URL 的位置写入代码,使用这个 URL 的时候就会执行 JavaScript 代码。
例如:

<a href="javascript:console.log('Hello')">点击</a>

href后边本来应该需要放一个url地址的,但是换成js语句也是可以使用的;
另外,浏览器的地址栏也支持JS协议,例如将javascript:console.log('Hello')放入地址栏,按回车键也可以执行这段代码。

网页元素接口

此部分介绍了各个网页元素具有的属性,方法等

常见的HTML事件

事件	    描述
onchange	HTML 元素已被改变
onclick	    用户点击了 HTML 元素
onmouseover	用户把鼠标移动到 HTML 元素上
onmouseout	用户把鼠标移开 HTML 元素
onkeydown	用户按下键盘按键
onload	    浏览器已经完成页面加载

JS搭配事件处理程序可以做什么?
用于处理,验证用户输入,用户动作和浏览器动作:

  • 每当页面加载时应该做的事情
  • 当页面被关闭时应该做的事情
  • 当用户点击按钮应该执行的动作
  • 当用户输入数据时应该被验证的内容
  • 等等

JS处理事件的不同方法有很多:

  • HTML事件属性可执行的JS代码
  • HTML事件属性能够调用JS函数
  • 您能够向HTML元素分配自己的事件处理函数
  • 您能够阻止事件被发送或被处理
  • 等等
    详见HTML DOM章节中学到更多有关事件和事件处理程序的知识。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值