1.什么是 DOM
DOM 全称为 Document Object Model,即文档对象模型。它是一套用来管理控制
html
文档的规则。而Document
节点则是一种具象化的表现形式。
假设我们把整个 html
文档看成一个对象,那么这个对象就是 Document 节点。
而我们如何操作、控制这个对象的标准,就是 DOM。
注意:DOM 中规定 html 页面中的 所有元素 都是节点。
2.怎么理解 document
document
节点又被叫做 document
对象。每个载入浏览器的 HTML 文档都会成为 document
对象。
document
对象使我们可以从脚本中对 HTML 页面的所有元素进行访问。
document
是 html 文档的根节点,每个网页都有自己的 document
节点。
window.document
属性就指向这个节点。也就是说只要浏览器开始载入 HTML 文档,这个对象就存在了,可以直接使用。
3.Document 节点属性
JavaScript 为 document 节点提供了很多属性方便我们更好的使用。相对用的比较多的有下面这些:
doctype、documentElement、body、head:返回文档内部的某个节点。
3.1 doctype
对于 HTML 文档来说 document
对象一般有两个子节点,第一个节点就是 doctype
。doctype
节点是一个对象,包含了当前文档类型信息。如果网页没有 DTD,该属性返回 null。
对于 HTML5 文档,doctype
节点就是 !DOCTYPE html>
。
语法:
document.doctype;
var doctype = document.doctype;
console.log(doctype); // <!doctype html>
console.log(doctype.name); // html
3.2 documentElement
documentElement
属性,表示当前文档的根节点。它通常是 document
节点的第二个子节点,紧跟在 document.doctype
后面。
对于 HTML 网页,该属性返回 HTML 节点。但是对我们来说一般都是通过 documentElement
节点来访问页面中的其它子节点。
语法:
document.documentElement;
console.log(document.documentElement);
3.3 body
body
属性返回当前文档的 body
或 frameset
节点,如果不存在这样的节点,就返回 null
。
这个属性是可写的,如果对其写入一个新的节点会导致原有的所有子节点被移除。暂时我们不做考虑。
语法:
document.body;
console.log(document.body);
3.4 head
head
属性返回当前文档的 head
节点,如果当前文档有多个 head
,则返回第一个
语法:
document.head;
console.log(document.head);
documentURI、URL、domain、lastModified、location、title、readyState:返回文档指定信息。
3.5 documentURI
documentURI
属性返回当前文档的网址。documentURI
属性所有文档都具备。
语法:
console.log(document.documentURI);
3.6 URL
documentURI
属性返回当前文档的网址。URL
属性只有 HTML 文档才具备。
语法:
document.URL
3.7 domain
domain
属性返回当前文档的域名。
例如某张网页的网址是 http://www.example.com/hello.html
,domain
属性就等于 www.example.com
。如果无法获取域名则返回 null
。
语法:
document.domain;
3.8 lastModified
lastModified
属性返回当前文档(网页)最后修改的时间戳,格式为字符串。
语法:
document.lastModified; // 05/21/2020 21:50:10
注意:lastModified
属性的值是字符串,所以不能用来直接比较。如果想要比较两个文档谁的日期更新,需要转成时间戳格式才能进行比较。
if (Date.parse(doc1.lastModified) > Date.parse(doc2.lastModified)) {
// ...
}
注意:Date.parse 方法能够将时间格式字符串转换成时间戳格式。
3.9 location
location
属性返回一个只读对象,提供了当前文档的 URL 信息。
返回完整的 URL:document.location.href
返回当前遵守的协议:document.location.protocol
返回当前页面域名 + 端口号:document.location.host
返回当前页面域名:document.location.hostname
返回当前页面端口号,如果不存在返回空:document.location.port
返回当前页面在服务器中的路径:document.location.pathname
返回当前页面 URL 中的查询字符串:document.location.search
跳转到另一个网址:document.location.assign("http://google.com")
location 中有关的其它内容:
以下方法效果相同,都能改变当前页面的 url:
location.assign("传递一个 url");
window.location = "传递一个 url";
location.href = "传递一个 url";
reload():重新加载当前显示的页面。
location.reload(false); // 优先从本地缓存重新加载
location.reload(true); // 优先从服务器重新加载
location 对象的 search
属性代表 URL 的查询字符串(包括 ?)
// 查询字符串为 ?id=x&sort=name
var search = window.location.search;
search = search.slice(1); // 得到 "id=x&sort=name"
search = search.split("&"); // 得到数组 ["id=x", "sort=name"]
3.10 title
title
属性返回当前文档的标题,该属性是可写的。
语法:
document.title;
document.title = "新标题";
3.11 characterSet
characterSet
属性返回渲染当前文档的字符集,比如 UTF-8、ISO-8859-1。
语法:
document.characterSet;
3.12 readyState
readyState
属性返回当前文档的状态。
共有三种可能值:
- 加载 HTML 代码阶段(尚未完成解析)是 “loading”。
- 加载外部资源文件阶段 “interactive”。
- 全部加载完成是 “complete”。
anchors、forms、images、links、scripts:返回文档内部特定节点的集合。
anchors
属性返回网页中所有指定了 name 属性的 a 节点元素。
forms
属性返回网页中所有表单。
images
属性返回网页中所有图片。
links
属性返回网页中所有的链接元素(即带有 href
属性的 a
标签)
scripts
属性返回网页中所有脚本。
var scripts = document.scripts;
if (scripts.length !== 0) {
console.log("当前网页有脚本!");
}
4.使用 Document 操作页面
4.1 选择页面元素
4.1.1 选择单个元素 方式1
querySelector()
方法返回匹配指定的 CSS 选择器的元素节点。如果有多个满足条件的节点,则返回第一个匹配的节点,如果没有发现匹配的节点则返回null
。
例如:
<a href="" class="aLink1">123</a>
<a href="" class="aLink2">456</a>
<script>
var aLink = document.querySelector("a");
console.log(aLink.innerHTML); // 123
</script>
注意:querySelector()
是匹配的选择器,如果选择器为类选择器时参数应该为".类名"
。
4.1.2 选择单个元素 方式2
- getElementById():返回匹配指定
id
属性的元素节点。 - getElementsByTagName():返回所有指定标签的元素。
- getElementsByClassName():返回符合指定类名的所有元素。
- getElementsByByName():用于选择拥有
name
属性的 HTML 元素。
4.1.3 选择所有元素
querySelectorAll()
方法用来选中页面元素,根据指定的选择器进行筛选。如果有多个元素满足条件,则返回这些元素构成的集合。
语法:
document.querySelectorAll("选择器名");
注意:
- 返回的结果是一个节点列表,不是数组,但能够像数组一样使用列表。
- 如果查询失败不是返回
null
,而是返回一个空的节点列表。
4.2 创建页面元素
4.2.1 创建元素
createElement()
生成 html 元素节点
语法:
document.createaElement("标签名");
var newP = document.createElement("p");
document.body.appendChild(newP);
直接创建一个按钮根本没办法直观看到,因此通过 appendChild()
的方式添加到 body
中。appendChild()
方法的作用能够将代码创建的元素添加到指定位置。
注意:这样创建的元素并没有内容,也没有属性,而是默认存在于内存中。在页面开发中的实用性较差。因此如果需要创建一个带有内容或者带有属性的元素就需要用到下面的两个方法来配合。
4.2.2 生成文本节点
createTextNode()
,参数为想要生成的文本内容。
语法:
var newP = document.createElement("p");
var pText = document.createTextNode("这是 p 的文本节点内容");
newP.appendChild(pText);
document.body.appendChild(newP);
4.2.3 生成新的属性对象节点
createAttribute()
生成新的属性对象节点,并返回它。
语法:
var newP = document.createElement("p");
var pText = document.createTextNode("这是 p 的文本节点内容");
newP.appendChild(pText);
var pStyle = document.createAttribute("style");
// 创建的属性节点使用 value = "" 的形式赋值
pStyle.value = "color: cyan;";
// 将属性绑定到节点上
newP.setAttributeNode(pStyle);
document.body.appendChild(newP);
注意:本方法创建的是属性节点,不是 CSS 属性节点。
4.3 操作页面的元素属性
CSS 和 JavaScript 是两个有着明确分工的领域,前者负责页面的视觉效果,后者负责与用户的行为互动。但它们毕竟同属网页开发中的技术,因此不可避免的会有交叉和相互配合。
所以在整体页面的布局中我们推荐使用 HTML + CSS 的方式来编写页面的结构和样式,在细节以及交互模块的编写过程中我们推荐使用 JS 的方式来辅助编写。
很显然,对于整个 HTML 页面来说,CSS 部分所代表的样式就显得更为重要一些。因为这些样式能够决定我们的页面整体显示效果,因此 JS 中也提供了几种操作页面元素属性的方法:
4.3.1 元素节点特性方法
getAttribute()
、setAttribute()
和 removeAttribute()
操作 Element 节点的 CSS 样式,最简单的方法之一就是使用节点对象的 getAttribute
方法和 removeAttribute
方法,读写或删除 HTML 元素的 style
属性。
语法:
getAttribute("属性名");
setAttribute("属性名", "属性值");
removeAttribute("属性名");
var div = document.querySelector("div");
div.setAttribute("style", "width: 200px; height: 200px;" +
"background-color: red; border: 1px solid black");
console.log(div.getAttribute("style"));
div.removeAttribute("style");
4.3.2 元素节点的 style
属性
Element 节点本身还提供 style
属性,用来操作 CSS 样式。style
属性指向一个对象,用来读写页面元素的行内 CSS 样式。
语法:
var divStyle = document.querySelector("div").style;
console.log(divStyle);
divStyle.width = "200px";
divStyle.height = "200px";
divStyle.border = "1px solid black";
divStyle.backgroundColor = "green";
divStyle.cssFloat = "left";
4.3.3 元素节点的 style
属性的 cssText
写法
style
对象的 cssText 属性可以用来读写或删除整个 style
属性。因此上面的写法可以改写成:
divStyle.cssText = "backgroundColor: green; float: right; width: 200px; height: 200px;"
+ "border: 1px solid black;"
注意:
- 该方式删除整个
style
属性可以用divStyle.cssText = '';
这种写法 cssText
对应的是 HTML 元素的style
属性,所以不用改写 CSS 属性名。
4.3.4 元素节点的 style
属性方法
setProperty()
、getPropertyValue()
和 removeProperty()
style
对象提供了三个方法来读写行内 CSS 规则:
setProperty(propertyName, value)
:设置某个 CSS 样式。getPropertyValue(propertyName)
:读取某个 CSS 属性。removeProperty(propertyName)
:删除某个 CSS 属性。
这三个方法的第一个参数,都是 CSS 属性名,且不用改写连词线。
语法:
var divStyle = document.querySelector("div").style;
divStyle.setProperty("background-color", "red");
divStyle.getPropertyValue("background-color");
divStyle.removeProperty("background-color");
5.Node
5.1 Node 概述
DOM 是文档对象模型的简称,它的基本思想是:
把结构化文档解析成一系列节点,再由这些节点解析成一个树状结构(DOM Tree)。
所有的节点和最终的树状结构,都有规范的对外接口,以达到使用编程语言操作文档的目的。
所以,DOM 可以理解成文档编程接口。
注意:严格地说,DOM 不属于 JavaScript,但是操作 DOM 是 JavaScript 最常见的任务。而 JavaScript 也是最常用于 DOM 操作的语言,所以 DOM 往往放在 JavaScript 中介绍。
node 是 DOM 的最小组成单位,一个文档的树形结构就是由各种不同类型的节点组成。
对于HTML 文档,node 主要有以下 6 种类型:
5.2 Node 的属性
5.2.1 通用属性
- nodeName:返回节点的名称
- nodeType:返回节点的类型
5.2.2 返回当前 node 的相关节点属性
- ownerDocument
返回当前节点所在的顶层文档对象,除document
节点会返回null
,其它节点全部返回#document
。 - nextSibling
返回紧跟在当前节点后面的第一个同级节点,如果当前节点后面没有同级节点则返回null
。
注意:该属性可以得到文本节点和评论节点。因此如果当前节点后面有空格,该属性会返回一个文本节点,内容为空格。 - previousSibling
返回当前节点的前一个同级节点,如果前面没有同级节点则返回null
。
注意:该属性可以得到文本节点和评论节点。因此如果当前节点后面有空格,该属性会返回一个文本节点,内容为空格。 - parentNode
parentNode
属性返回当前节点的父节点,如果当前节点没有父节点,则返回null
(document
节点)。
注意:一般情况下,一个节点的父节点只可能是三种类型:element
节点、document
节点和documentFragment
节点。 - parentElement
parentElement
属性返回当前节点的父元素节点,如果当前节点没有父节点,或者父节点类型不是Element
节点,则返回null
。
注意:parentElement
是 IE 所独有的属性,其能实现的功能parentNode
都能实现。可以说parentNode
是parentElement
的标准版本。
5.2.3 返回 node 内容属性
- textContent
textContent
属性返回当前节点和它所有后代节点的文本内容。
注意:textContent
属性,自动忽略当前节点内部的 HTML 标签,返回所有文本內容(包含空格)。 - nodeValue
nodeValue
属性返回或设置当前节点的值,格式为字符串。
但是nodeValue
只对 Text 节点、Comment
节点、XML 文档的 CDATA 节点有效,其它类型的节点一律返回null
。
因此,nodeValue
属性只用于 Text 节点。对于那些返回null
的节点,设置nodeValue
属性是无效的
5.2.4 返回当前 node 子节点相关信息
- childNodes
该属性会返回一个节点集合(NodeList),节点集合包括当前节点的所有子节点。
需要指出的是,除了 HTML 中的元素节点之外,该属性返回的还包括 Text 节点和 Comment 节点。
如果当前节点不包括任何子节点,则返回一个空的 NodeList 集合
注意:由于 NodeList 对象是一个动态集合,一旦子节点发生变化,立刻会反映在返回结果当中。 - firstChild
该属性返回当前节点的第一个子节点,如果当前节点没有子节点,则返回null
。需要注意的是,除了 HTML 元素子节点,该属性还包括文本节点和评论节点。 - lastChild
该属性返回当前节点的最后一个子节点,如果当前节点没有子节点,则返回null
。
5.3 Node 的方法
5.3.1 appendChild()
appendChild()
方法接收一个节点对象为参数,将其作为最后一个子结点,插入当前节点。
var p = document.createElement("p");
document.body.appendChild(p);
5.3.2 hasChildNodes()
hasChildNodes()
方法返回一个布尔值,表示当前节点是否有子节点。
var foo = document.getElementById("foo");
if (foo.hasChildNodes()) {
}
5.3.3 cloneNode()
cloneNode()
方法用于克隆一个节点。它接收一个布尔值作为参数,表示是否同时克隆子节点,默认是 false
,即不克隆子节点(浅克隆)。如果传入 true
会克隆子节点(深克隆)。
注意:克隆一个节点,会拷贝该节点的所有属性,但不包括 addEventListener()
和 on-属性
(例如 onclick = function() {}
) 这种节点上的回调函数。
5.3.4 insertBefore()
insertBefore()
方法用于将某个节点插入当前节点的指定位置。
它接收两个参数,第一个参数是所要插入的节点,第二个参数是当前节点的子节点,新的节点将插在这个节点的前面。该方法返回被插入的新节点。
var ul = document.querySelector("ul");
var li = document.createElement("li");
var liText = document.createTextNode("1");
li.appendChild(liText);
ul.insertBefore(li, ul.firstChild);
上面的代码作用是将新建的 li
插入到 ul
的第一个子节点的前面。
5.3.5 removeChild()
removeChild()
方法接收一个子节点作为参数,用于从当前节点移除该节点,并且返回被移除的节点。
5.3.6 replaceChild()
replaceChild()
方法用于将一个新的节点,替换当前节点的某个子节点。
它接收连个参数,第一个参数是用来替换的新节点,第二个参数是将要被替换走的子节点,最终返回被替换走的那个节点。
语法:
var replaceNode = parentNode.replaceChild(newChild, oldChild);
例如:
var div = document.querySelector("div");
var span = document.createElement("span");
span.innerHTML = "这是一个 span";
document.querySelector("button").onclick = function() {
div.parentNode.replaceChild(span, div);
}
以上代码的作用是使用新创建出的 span
的內容替代 div
的內容。
5.3.7 contains
contains()` 方法接收一个节点作为参数,返回一个布尔值。该方法用于判断 参数节点 是否为 当前节点 的 子节点。
5.3.8 isEqualNode
isEqualNode()
方法返回一个布尔值,用于检查两个节点是否相等。
语法:
node.isEqualNode("待比较节点");
注意:所谓相等是指两个节点的类型相同、属性相同、子节点相同。
5.4 Node 其它內容
5.4.1 HTML 元素
html 元素是网页的根元素,document.documentElement
就指向这个元素。JS 中关于 html 元素也提供了一些相关的属性和方法来帮助我们更好的操作:
- 视图窗口大小:
clientWidth
属性,clientHeight
属性 - html 元素大小:
offsetWidth
属性,offsetHeight
属性
var html = document.documentElement;
// 当前窗口的大小多大,clientXXX 的值就是多大
console.log("html clientWidth: " + html.clientWidth);
console.log("html clientHeight: " + html.clientHeight);
// HTML 元素多大,offsetXXX 的值就是多大
console.log("html offsetWidth: " + html.offsetWidth);
console.log("html offsetHeight: " + html.offsetHeight);
5.4.2 元素位置相关属性
- offsetParent
该属性表示获取 当前元素 的最靠近的、并且 CSS 的position
属性不等于static
的父元素。
运行结果:<p id="p-id" style="position: relative;"> <span id="span-id"> <a href="#" id="a-id">test-a</a> </span> </p> var a = document.querySelector("#a-id"); var aParent = a.offsetParent; console.log(aParent);
- offsetTop:当前 HTML 元素左上角相对于
offsetParent
的垂直位移。 - offsetLeft:当前 HTML 元素左上角相对于
offsetParent
的水平位移。
5.4.3 querySelector 和 getElementsBy 系列的方法对比
- 两者的 W3C 标准不同
querySelector
系列属于 W3C 中的 Selectors API(JS)规范。
getElementsBy
系列属于 W3C 中的 DOM 规范。 - 两者浏览器的兼容不同
querySelector
系列基本能被所有浏览器支持。
getElementsBy
系列通常只有在考虑兼容性的时候才被提起。 - 接收参数不同
querySelector
系列接收的参数是一个 CSS 选择器名。
getElementsBy
系列接收的参数只能是单一的 className、tagName、id。 - 返回值不同
querySelectorAll
返回的是一个静态节点列表(Static NodeList)
getElementsBy
系列返回的是一个动态节点列表(Live NodeList)