DOM总结

222 阅读10分钟

DOM

Node

node节点属性

  • nodeType 节点类型
  • nodeName 标签名,值取决于节点类型
  • nodeValue 值取决于节点类型
  • childNodes NodeList实例
  • parentNode 指向父节点
  • previousSibling 前一个兄弟节点
  • nextSibling 后一个兄弟节点
  • firstChild 第一个子节点
  • lastChild 最后一个子节点
  • ownerDocument 指向代表整个文档的文档节点 的指针

node节点方法

  • hasChildNodes() 返回true,表示存在子节点
  • appendChild(),用于在 childNodes 列表末尾添加节点,返回新增的节点
let returnedNode = someNode.appendChild(newNode);
alert(returnedNode == newNode); // true
alert(someNode.lastChild == newNode); // true
  • insertBefore() 这个方法接收两个参数:要插入的节点和参照节点。调用这个方法后,要插入的节点会变成参照节点的前一个同胞节点,并被返回。如果参照节点是 null,则 insertBefore()与 appendChild()效果相同
// 作为最后一个子节点插入
returnedNode = someNode.insertBefore(newNode, null);
alert(newNode == someNode.lastChild); // true
// 作为新的第一个子节点插入
returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
alert(returnedNode == newNode); // true
alert(newNode == someNode.firstChild); // true
// 插入最后一个子节点前面
returnedNode = someNode.insertBefore(newNode, someNode.lastChild);
alert(newNode == someNode.childNodes[someNode.childNodes.length - 2]); // true
  • replaceChild()

replaceChild()方法接收两个参数:要插入的节点和要替换的节点。要替换的节点会被返回并从文档树中完全移除,要插入的节点会取而代之。

// 替换第一个子节点
let returnedNode = someNode.replaceChild(newNode, someNode.firstChild);
// 替换最后一个子节点
returnedNode = someNode.replaceChild(newNode, someNode.lastChild); 
  • removeChild() 这个方法接收一个参数,即要移除的节点。被移除的节点会被返回
// 删除第一个子节点
let formerFirstChild = someNode.removeChild(someNode.firstChild);
// 删除最后一个子节点
let formerLastChild = someNode.removeChild(someNode.lastChild); 
  • cloneNode() 接收一个布尔值参数,表示是否深复制。在传入 true 参数时,会进行深复制,即复制节点及其整个子 DOM 树。如果传入 false,则只会复制调用该方法的节点。复制返回的节点属 于文档所有,但尚未指定父节点,所以可称为孤儿节点(orphan)。可以通过 appendChild()、insertBefore()或 replaceChild()方法把孤儿节点添加到文档中。
<ul>
 <li>item 1</li>
 <li>item 2</li>
 <li>item 3</li>
</ul>

如果myList保存着对这个<ul>元素的引用,则下列代码展示了使用cloneNode()方法的两种方式:

let deepList = myList.cloneNode(true);
alert(deepList.childNodes.length); // 3(IE9 之前的版本)或 7(其他浏览器)
let shallowList = myList.cloneNode(false);
alert(shallowList.childNodes.length); // 0 

Document

在浏览器中,文档对象 document 是HTMLDocument 的实例(HTMLDocument 继承 Document),表示整个 HTML 页面。 document 是 window对象的属性,因此是一个全局对象。特性如下:

  • nodeType: 9
  • nodeName: "#document"
  • nodeValue: null
  • parentNode: null
  • ownerDocument: null
  • 子节点可以是 DocumentType(最多一个)、Element(最多一个 html)、ProcessingInstruction或 Comment 类型。

document属性

  • documentElement 获取html元素
  • body 获取body元素
  • doctype 获取
  • title 浏览器标签栏的标题
// 读取文档标题
let originalTitle = document.title;
// 修改文档标题
document.title = "New page title"; 
  • head 获取head元素
  • characterSet characterSet 属性表示文档实际使用的字符集,也可以用来指定新字符集。这个属性的默认值是"UTF-16",但可以通过元素或响应头,以及新增的 characterSeet 属性来修改。
console.log(document.characterSet); // "UTF-16"
document.characterSet = "UTF-8"; 
  • URL 包含当前页面的完整 URL(地址栏中的 URL)
  • domain 包含页面的域名
  • referrer 包含链接到当前页面的那个页面的 URL。如果当前页面没有来源,则 referrer 属性包含空字符串。 URL 跟域名是相关的。比如,如果 document.URL 是 http://www.wrox.com/WileyCDA/,则 document.domain 就是 www.wrox.com。 这三个属性只有domain可以设置,但也有限制。
  • anchors 包含文档中所有带 name 属性的<a>元素。
  • forms 包含文档中所有<form>元素(与 document.getElementsByTagName ("form")返回的结果相同)。
  • images 包含文档中所有<img>元素(与 document.getElementsByTagName ("img")返回的结果相同)。
  • links 包含文档中所有带 href 属性的<a>元素。 HTMLCollection都会实时更新
  • activeElement,始终包含当前拥有焦点的 DOM 元素。
let button = document.getElementById("myButton");
button.focus(); //让元素获取焦点
console.log(document.activeElement === button); // true 
  • readyState document.readyState 属性有两个可能的值:
    • loading,表示文档正在加载;
    • complete,表示文档加载完成。
if (document.readyState == "complete"){
 // 执行操作
}

document方法

选择元素

  • getElementById() 接收id参数,返回满足条件的第一个元素
<div id="myDiv">Some text</div>
let div = document.getElementById("myDiv"); // 取得对这个<div>元素的引用
  • getElementsByTagName() 接收一个参数,即要获取元素的标签名,返回包含零个或多个元素的 NodeList。不区分大小写。 HTML 文档中,这个方法返回一个 HTMLCollection 对象。
let images = document.getElementsByTagName("img");
  • getElementByName() 这个方法会返回具有给定 name 属性的所有元素。最常用于单选按钮,因为同一字段的单选按钮必须具有相同的 name 属性才能确保把正确的值发送给服务器。
let radios = document.getElementsByName("color");
  • querySelector querySelector()方法接收 CSS 选择符参数,返回匹配该模式的第一个后代元素,如果没有匹配项则返回 null。
// 取得<body>元素
let body = document.querySelector("body");
// 取得 ID 为"myDiv"的元素
let myDiv = document.querySelector("#myDiv");
// 取得类名为"selected"的第一个元素
let selected = document.querySelector(".selected");
// 取得类名为"button"的图片
let img = document.body.querySelector("img.button");

在 Document 上使用 querySelector()方法时,会从文档元素开始搜索;在 Element 上使用 querySelector()方法时,则只会从当前元素的后代中查询。

  • querySelectorAll() querySelectorAll()方法跟 querySelector()一样,也接收一个用于查询的参数,但它会返回 所有匹配的节点,而不止一个。这个方法返回的是一个 NodeList 的静态实例。 再强调一次,querySelectorAll()返回的 NodeList 实例一个属性和方法都不缺,但它是一个静态的“快照”,而非“实时”的查询。这样的底层实现避免了使用 NodeList 对象可能造成的性能问题。
  • getElementsByClassName() getElementsByClassName()方法接收一个参数,即包含一个或多个类名的字符串,返回类名中包含相应类的元素的 NodeList。如果提供了多个类名,则顺序无关紧要。
// 取得所有类名中包含"username"和"current"元素
// 这两个类名的顺序无关紧要
let allCurrentUsernames = document.getElementsByClassName("username current");
// 取得 ID 为"myDiv"的元素子树中所有包含"selected"类的元素
let selected = document.getElementById("myDiv").getElementsByClassName("selected");

创建元素

  • createElement 创建元素
let div = document.createElement("div");
div.id = "myNewDiv";
div.className = "box";
document.body.appendChild(div);
  • createTextNode() 创建文本节点
let element = document.createElement("div");
element.className = "message";
let textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
document.body.appendChild(element);

遍历

  • createNodeIterator() 这个方法接收以下 4 个参数:
    • root,作为遍历根节点的节点。
    • whatToShow,数值代码,表示应该访问哪些节点。
      • NodeFilter.SHOW_ALL,所有节点。
      • NodeFilter.SHOW_ELEMENT,元素节点。
      • NodeFilter.SHOW_TEXT,文本节点。
    • filter,NodeFilter 对象或函数,表示是否接收或跳过特定节点。
    • entityReferenceExpansion,布尔值,表示是否扩展实体引用。这个参数在 HTML 文档中没有效果,因为实体引用永远不扩展。

whatToShow 参数是一个位掩码,通过应用一个或多个过滤器来指定访问哪些节点。这个参数对应 的常量是在 NodeFilter 类型中定义的。

<div id="div1">
     <p><b>Hello</b> world!</p>
     <ul>
         <li>List item 1</li>
         <li>List item 2</li>
         <li>List item 3</li>
     </ul>
</div>

假设想要遍历<div>元素内部的所有元素,那么可以使用如下代码:

let div = document.getElementById("div1");
let iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, null, false);
let node = iterator.nextNode();
while (node !== null) {
 console.log(node.tagName); // 输出标签名
 node = iterator.nextNode();
} 

其他

  • hasFocus() 该方法返回布尔值,表示文档是否拥有焦点
  • write()
  • writeln()
  • open()
  • close()

Element类型

网页中的元素类型,特性如下

  • nodeType: 1
  • nodeName: 元素的标签名
  • nodeValue: null
  • parentNode: Document或Element对象
  • 子节点可以是 Element、Text、Comment、ProcessingInstruction、CDATASection、EntityReference 类型。

element属性

  • tagName, 获取标签名,与nodeName返回值相同,都返回大写的标签名
  • id,元素在文档中的唯一标识符;
  • title,包含元素的额外信息,通常以提示条形式展示;
  • className,相当于 class 属性,用于指定元素的 CSS 类(因为 class 是 ECMAScript 关键字,所以不能直接用这个名字)。
  • classList 获取元素class的集合,classList 是一个新的集合类型 DOMTokenList 的实例。与其他 DOM 集合类型一样,DOMTokenList也有 length 属性表示自己包含多少项,也可以通过 item()或中括号取得个别的元素。DOMTokenList 还增加了以下方法
    • add(value),向类名列表中添加指定的字符串值 value。如果这个值已经存在,则什么也不做。
    • contains(value),返回布尔值,表示给定的 value 是否存在。
    • remove(value),从类名列表中删除指定的字符串值 value。
    • toggle(value),如果类名列表中已经存在指定的 value,则删除;如果不存在,则添加。
// 删除"disabled"类
div.classList.remove("disabled");
// 添加"current"类
div.classList.add("current");
// 切换"user"类
div.classList.toggle("user");
// 检测类名
if (div.classList.contains("bd") && !div.classList.contains("disabled")){
 // 执行操作
)
// 迭代类名
for (let class of div.classList){
 doStuff(class);
} 
<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>
alert(div.className); // "bd" 
  • innerHTML 读取时,dom变字符串;返回所有后代元素的字符串,具体格式因浏览器而异,写入时,字符串变dom。
  • style 通过js来读写样式
let myDiv = document.getElementById("myDiv");
// 设置背景颜色
myDiv.style.backgroundColor = "red";
// 修改大小
myDiv.style.width = "100px";
myDiv.style.height = "200px";
// 设置边框
myDiv.style.border = "1px solid black";
<div id="myDiv" style="background-color: blue; width: 10px; height: 25px"></div>
console.log(myDiv.style.backgroundColor); // "blue"
console.log(myDiv.style.width); // "10px"
console.log(myDiv.style.height); // "25px" 

element方法

  • getAttribute() style和事件有差异,不常用
  • setAttribute()
  • removeAttribute()
let div = document.getElementById("myDiv");
alert(div.getAttribute("id")); // "myDiv"
  • scrollIntoView()
    scrollIntoView()方法存在于所有 HTML 元素上,可以滚动浏览器窗口或容器元素以便包含元素进入视口。这个方法的参数如下:
    • alignToTop 是一个布尔值。
      • true:窗口滚动后元素的顶部与视口顶部对齐。
      • false:窗口滚动后元素的底部与视口底部对齐。
    • scrollIntoViewOptions 是一个选项对象。
      • behavior:定义过渡动画,可取的值为"smooth"和"auto",默认为"auto"。
      • block:定义垂直方向的对齐,可取的值为"start"、"center"、"end"和"nearest",默认为 "start"。
      • inline:定义水平方向的对齐,可取的值为"start"、"center"、"end"和"nearest",默认为 "nearest"。
    • 不传参数等同于 alignToTop 为 true。
// 确保元素可见
document.forms[0].scrollIntoView();
// 同上
document.forms[0].scrollIntoView(true);
document.forms[0].scrollIntoView({block: 'start'});
// 尝试将元素平滑地滚入视口
document.forms[0].scrollIntoView({behavior: 'smooth', block: 'start'}); 

Text类型

文本节点,特性如下:

  • nodeType 等于 3;
  • nodeName 值为"#text";
  • nodeValue 值为节点中包含的文本;
  • parentNode 值为 Element 对象;
  • 不支持子节点。

text方法

  • appendData(text),向节点末尾添加文本 text;
  • deleteData(offset, count),从位置 offset 开始删除 count 个字符;
  • insertData(offset, text),在位置 offset 插入 text;
  • replaceData(offset, count, text),用 text 替换从位置 offset 到 offset + count 的文本;
  • splitText(offset),在位置 offset 将当前文本节点拆分为两个文本节点;
  • substringData(offset, count),提取从位置 offset 到 offset + count 的文本。
let textNode = div.firstChild; // 或 div.childNodes[0]
// 修改文本节点
div.firstChild.nodeValue = "Some other message";

DOM编程

动态脚本

function loadScript(url) {
 let script = document.createElement("script");
 script.src = url;
 document.body.appendChild(script);
}
// 然后,就可以像下面这样加载外部 JavaScript 文件了:
loadScript("client.js");

动态样式

function loadStyles(url){
 let link = document.createElement("link");
 link.rel = "stylesheet";
 link.type = "text/css";
 link.href = url;
 let head = document.getElementsByTagName("head")[0];
 head.appendChild(link);
}
// 然后就可以这样调用这个 loadStyles()函数了:
loadStyles("styles.css");

NodeList

NodeList 就是基于 DOM 文档的实时查询。下面的代码会导致无穷循环:

let divs = document.getElementsByTagName("div");
for (let i = 0; i < divs.length; ++i){
 let div = document.createElement("div");
 document.body.appendChild(div);
}

元素尺寸

偏移尺寸

包含元素在屏幕上占用的所有视觉空间。元素在页面上的视觉空间由其高度和宽度决定,包括所有内边距、滚动条和边框(但不包含外边距)。以下 4 个属性用于取得元素的偏移尺寸。

  • offsetHeight,元素在垂直方向上占用的像素尺寸,包括它的高度、水平滚动条高度(如果可见)和上、下边框的高度。
  • offsetLeft,元素左边框外侧距离包含元素左边框内侧的像素数。只读属性
  • offsetTop,元素上边框外侧距离包含元素上边框内侧的像素数。只读属性
  • offsetWidth,元素在水平方向上占用的像素尺寸,包括它的宽度、垂直滚动条宽度(如果可见)和左、右边框的宽度。 其中,offsetLeft 和 offsetTop 是相对于包含元素的,包含元素保存在 offsetParent 属性中。 offsetParent 不一定是 parentNode。比如,<td>元素的 offsetParent 是作为其祖先的<table>元素,因为<table>是节点层级中第一个提供尺寸的元素。

image.png

客户端尺寸

  • clientWidth 是内容区宽度加左、右内边距宽度
  • clientHeight 是内容区高度加上、下内边距高度

image.png 客户端尺寸实际上就是元素内部的空间,因此不包含滚动条占用的空间。这两个属性最常用于确定浏览器视口尺寸,即检测 document.documentElement 的 clientWidth 和 clientHeight。这两个属性表示视口(<html>或<body>元素)的尺寸。

滚动尺寸

  • scrollHeight,没有滚动条出现时,元素内容的总高度
  • scrollLeft,内容区左侧隐藏的像素数,设置这个属性可以改变元素的滚动位置
  • scrollTop,内容区顶部隐藏的像素数,设置这个属性可以改变元素的滚动位置
  • scrollWidth,没有滚动条出现时,元素内容的总宽度

image.png

元素位置

  • clientX、clientY

点击位置距离当前body可视区域的x,y坐标

  • pageX、pageY

对于整个页面来说,包括了被卷去的body部分的长度

  • screenX、screenY

点击位置距离当前电脑屏幕的x,y坐标

  • offsetX、offsetY

相对于带有定位的父盒子的x,y坐标