DOM的重要知识点:全是干货

DOM方面

1、DOM构成,Node类型

DOM是文档对象模型,是由多层节点构成的文档,开发者可以通过它对页面进行增删改查。

任何的HTML XML文档都可以用DOM表示为一个由节点构成的层级结构。

所有DOM节点都会实现Node接口,Node接口表现为Node类型,一共有12个,比较常用的就是元素节点和文本节点。

1、nodeName和nodeValue

nodeName:保存着节点的信息,如果节点是元素节点,则 nodeName 属性返回标签名。 如果节点是属性节点,则 nodeName 属性返回属性的名称

nodeType:nodeType 属性返回以数字值返回指定节点的节点类型

2、childNodes属性与NodeList对象

childNodes属性是节点的关系属性

每一个节点都有一个childNodes属性,包含着NodeList实例,NodeList是类数组对象,实质上是一个对 DOM 结构的查询,存储按位置存取的有序节点,有length属性,还可以用中括号和item()获取它的值。

childNodes

 //获取someNode的一个子节点的元素
 let firstChild = someNode.childNodes[0];
 let secondChild = someNode.childNodes.item(1);
 //获取节点的长度
 let count = someNode.childNodes.length;
3、将NodeList对象转换成数组
 //方法一:通过Array.prototype.slice()
 let arrayOfNodes = Array.prototype.slice.call(someNode.childNodes,0);
 //方法二:通过Array.from
 let arrOfNodes = Array.from(someNode.childNodes);
4、parentNode属性

(firstChild|lastChild)及同胞节点previousSibling\nextSibling

每个节点都有一个 parentNode 属性,指向其 DOM 树中的父元素,firstChild 和 lastChild 分别指向childNodes 中的第一个和最后一个子节点;

而使用 previousSibling 和 nextSibling 可以在列表的兄弟节点间导航,previousSibling指向上一个节点,nextSibling指向下一个节点,无上下节点兄弟,则值为空。

5、如何操作节点:节点的增删改

appendChild()/insertBefore()/replaceChild()

因为所有关系指针都是只读的,所以 DOM 又提供了一些操纵节点的方法。

appendChild()方法:用于在childNodes末尾添加新的节点。添加的新节点会更新相关的关系指针(比如lastChild)。appendChild()方法返回新添加的节点::

 let returnedNode = someNode.appendChild(newNode); 
 alert(returnedNode == newNode); // true 
 alert(someNode.lastChild == newNode); // true
 ​
 //将div元素插入到body里面
 document.body.appendChild(div)

注意的是,如果是添加已存在的节点,比如把firstNode传给appendChild(),则这个节点会变成最后一个节点

 // 假设 someNode 有多个子节点
 let returnedNode = someNode.appendChild(someNode.firstChild); 
 alert(returnedNode == someNode.firstChild); // false 
 alert(returnedNode == someNode.lastChild); // 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(要插入的节点,替换的节点)方法:要替换的节点会被返回并从文档树中完全移除,要插入的节点会取而代之,所有关系指针都会从被替换的节点复制过来

 // 替换第一个子节点
 let returnedNode = someNode.replaceChild(newNode, someNode.firstChild);

removeChild(需要移除的节点):删除节点

 // 删除最后一个子节点
 let formerLastChild = someNode.removeChild(someNode.lastChild);

cloneNode(布尔值):克隆节点:接收一个布尔值参数,表示是否深复制::true-深复制;false-浅复制。这个方法只复制 HTML 属性。了解即可。

2、Document类型

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

  1. nodeType 等于 9;

  2. nodeName 值为"#document";

  3. nodeValue 值为 null;

  4. parentNode 值为 null;

  5. ownerDocument 值为 null;

  6. 子节点可以是 DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction或 Comment 类型。

Document 类型可以表示 HTML 页面或其他 XML 文档,但最常用的还是通过 HTMLDocument 的实例取得 document 对象。document 对象可用于获取关于页面的信息以及操纵其外观和底层结构。

1、Document的文档子节点

documentElement/body属性

1.documentElement属性

documentElement 属性,始终指向 HTML 页面中的<html>元素

document.childNodes 中始终有<html>元素,但使用 documentElement 属性可以更快更直接地访问该元素

比如有下面这个页面:

<html>

<body> </body>

</html>

浏览器解析完之后,文档只有一个子节点-<html>元素,可以通过两种方式访问

 let html = document.documentElement; // 取得对<html>的引用
 alert(html === document.childNodes[0]); // true 
 alert(html === document.firstChild); // true

2.body属性:指向<body>元素

 let body = document.body; // 取得对<body>的引用

3.docType:获取doctype属性

2、文档信息相关属性方法

tittle/url/domain/referrer

tittle属性:包含<title>元素中的文本,通过这个属性可以读写页面的标题,修改 title 属性并不会改变<title>元素

 // 读取文档标题
 let originalTitle = document.title;
 // 修改文档标题
 document.title = "New page title";

URL:URL 包含当前页面的完整 URL(地址栏中的 URL)

domain:domain 包含页面的域名

referrer:referrer 包含链接到当前页面的那个页面的 URL。

在这些属性中,只有 domain 属性是可以设置的。

 // 取得完整的 URL 
 let url = document.URL; 
 // 取得域名
 let domain = document.domain; 
 // 取得来源
 let referrer = document.referrer;

domain用法(了解):当页面中包含来自某个不同子域的窗格(<frame>)或内嵌窗格(<iframe>)时,设置document.domain 是有用的。因为跨源通信存在安全隐患,所以不同子域的页面间无法通过 JavaScript通信。此时,在每个页面上把 document.domain 设置为相同的值,这些页面就可以访问对方的 JavaScript对象了。

3、定位元素,执行操作

getElementById()和 getElementsByTagName()

getElementById()

方法接收一个参数,即要获取元素的 ID,如果找到了则返回这个元素,如果没找到则返回 null。存在多个具有相同 ID 的元素,则 getElementById()返回在文档中出现的第一个元素。

getElementsByTagName()

方法接收一个参数,即要获取元素的标签名,返回包含零个或多个元素的 NodeList(实时列表)。 HTML 文档中,这个方法返回一个HTMLCollection 对象。HTMLCollection 还提供了除索引之外的另一种获取列表项的方式:namedItem()。

HTMLCollection 对象而言,中括号既可以接收数值索引,也可以接收字符串索引。而在后台,数值索引会调用 item(),字符串索引会调用 namedItem()。

 <div id="myDiv">Some text</div>
 let div = document.getElementById("myDiv"); // 取得对这个<div>元素的引用
 ​
 //取得页面中所有的<img>元素并返回包含它们的 HTMLCollection
 let images = document.getElementsByTagName("img");
 alert(images.length); // 图片数量
 alert(images[0].src); // 第一张图片的 src 属性
 alert(images.item(0).src); // 同上
 ​
 /*HTMLCollection 对象还有一个额外的方法 namedItem(),可通过标签的 name 属性取得某一项的引用,例如,假设页面中包含如下的<img>元素:*/
 <img src="myimage.gif" name="myImage">
 let myImage = images.namedItem("myImage");
 //对于name属性的元素,还可以直接使用中括号来获取
 let myImage = images["myImage"];
getElementsByName()

会返回具有给定 name 属性的所有元素,常用于单选按钮,因为同一字段的单选按钮必须具有相同的 name 属性才能确保把正确的值发送给服务器

其他特殊的集合

document 对象上还暴露了几个特殊集合,这些集合也都是 HTMLCollection 的实例。这些集合是访问文档中公共部分的快捷方式,列举如下。

document.anchors 包含文档中所有带 name 属性的<a>元素。

document.forms 包含文档中所有<form>元素

document.images 包含文档中所有<img>元素(与document.getElementsByTagName ("img")

document.links 包含文档中所有带 href 属性的<a>元素。

文档写入:

write()、writeln()、open()和 close()

write()和 writeln()方法都接收一个字符串参数,可以将这个字符串写入网页中。write()简单地写入文本,而 writeln()还会在字符串末尾追加一个换行符(\n)。这两个方法可以用来在页面加载期间向页面中动态添加内容

 <html> 
 <head> 
  <title>document.write() Example</title> 
 </head> 
 <body> 
  <p>The current date and time is: 
  <script type="text/javascript"> 
  document.write("<strong>" + (new Date()).toString() + "</strong>"); 
  </script> 
 </p> 
 </body> 
 </html>

open()和 close()方法分别用于打开和关闭网页输出流。不太重要,了解即可。

3、Element类型

最常用的类型,表示元素,对外暴露出访问元素标签名、子节点和属性的能力。

特征:

 nodeType 等于 1;

 nodeName 值为元素的标签名;

 nodeValue 值为 null;

 parentNode 值为 Document 或 Element 对象;

 子节点可以是 Element、Text、Comment、ProcessingInstruction、CDATASection、EntityReference 类型。

可以通过 nodeName 或 tagName 属性来获取元素的标签名

 <div id="myDiv"></div> 
 //可以像这样取得这个元素的标签名:
 let div = document.getElementById("myDiv"); 
 alert(div.tagName); // "DIV" 
 alert(div.tagName == div.nodeName); // true
1,HTML元素

 id,元素在文档中的唯一标识符;

 title,包含元素的额外信息,通常以提示条形式展示;

 lang,元素内容的语言代码(很少用);

 dir,语言的书写方向("ltr"表示从左到右,"rtl"表示从右到左,同样很少用);

 className,相当于 class 属性,用于指定元素的 CSS 类(因为 class 是 ECMAScript 关键字,所以不能直接用这个名字)。

 <div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>
 //修改
 div.id = "someOtherId"; 
 div.className = "ft"; 
 div.title = "Some other text"; 
 div.lang = "fr"; 
 div.dir ="rtl";
2,取得属性getAttribute()

getAttribute()主要用于取得自定义属性的值,其他时候一般使用对象属性(style属性和事件处理程序,这个函数表现不一样)

重点:id值.getAttribute("属性")

 <body>
     <div id = 'm1' class = 'name'></div>
     <body>
         <script>
        let m2= m1.getAttribute("class")
          console.log(m2)        //name
         </script>
3、设置属性setAttribute()

接收两个参数:要设置的属性名和属性的值。

div.setAttribute("id", "someOtherId");

4、删除属性 removeAttribute()

会把整个属性完全从元素中去掉

5、attributes属性(中高级看,初级了解)

attributes 属性包含一个 NamedNodeMap 实例。元素的每个属性都表示为一个 Attr 节点,并保存在这个 NamedNodeMap 对象中。NamedNodeMap 对象包含下列方法:

 getNamedItem(name),返回 nodeName 属性等于 name 的节点;

 removeNamedItem(name),删除 nodeName 属性等于 name 的节点;

 setNamedItem(node),向列表中添加 node 节点,以其 nodeName 为索引;

 item(pos),返回索引位置 pos 处的节点

6、创建元素 createElement()

document.createElement()方法创建新元素,这个方法接收一个参数,即要创建元素的标签名,同时也会把新元素的 ownerDocument 属性设置为 document,此时,可以再为其添加属性、添加更多子元素

 //创建一个新的div元素
 let div = document.createElement("div")
 //添加一些属性
 div.id = "myNewDiv";

在新元素上设置这些属性只会附加信息。因为这个元素还没有添加到文档树,所以不会影响浏览器显示。要把元素添加到文档树,可以使用 appendChild()、insertBefore()或 replaceChild()。比如,以下代码会把刚才创建的元素添加到文档的<body>元素中:

 document.body.appendChild(div);

7、选择合适的元素(元素后代
 <ul id="myList"> 
  <li>Item 1</li> 
  <li>Item 2</li> 
  <li>Item 3</li> 
 </ul>

在解析以上代码时,<ul>元素会包含 7 个子元素,其中 3 个是<li>元素,还有 4 个 Text 节点(表示<li>元素周围的空格)。因此在执行操作时,通常会检测一下节点的nodeType,是元素节点或者某一类型节点再进行操作

 for(let i = 0,len = element.childNodes.length;i<len;++i){
     if(element.childNodes[i].nodeType ==1){
         //执行某个操作
     }
 }

以上代码会遍历某个元素的子节点,并且只在 nodeType 等于 1(即 Element 节点)时执行某个操作。

取得某个元素的子节点

 let ul = document.getElementById("myList");
 let items = ul.getElementByTagName("li");

4、Text类型

Text 节点由 Text 类型表示,包含按字面解释的纯文本,也可能包含转义后的 HTML 字符,但不含 HTML 代码。Text 类型的节点具有以下特征:

 nodeType 等于 3;

 nodeName 值为"#text";

 nodeValue 值为节点中包含的文本;

 parentNode 值为 Element 对象;

 不支持子节点。

Text 节点中包含的文本可以通过 nodeValue 属性访问,也可以通过 data 属性访问,这两个属性包含相同的值。修改 nodeValue 或 data 的值,也会在另一个属性反映出来。

文本节点暴露了以下操作文本的方法:

 appendData(text),向节点末尾添加文本 text

 deleteData(offset, count),从位置 offset 开始删除 count 个字符;

 insertData(offset, text),在位置 offset 插入 text

 replaceData(offset, count, text),用 text 替换从位置 offsetoffset + count

文本;

 splitText(offset),在位置 offset 将当前文本节点拆分为两个文本节点;

 substringData(offset, count),提取从位置 offsetoffset + count 的文本。

除了这些方法,还可以通过 length 属性获取文本节点中包含的字符数量。这个值等于 nodeValue. length 和 data.length。

 <!-- 有内容,因此有一个文本节点 --> 
 <div>Hello World!</div>
 //获取文本节点
 let textNode = div.firstChild;//或div.childNode[0]
 //修改文本节点
 div.firstChild.NodeValue = "change text"
 /*修改文本节点还有一点要注意,就是HTML 或 XML 代码(取决于文档类型)会被转换成实体编码,即小于号、大于号或引号会被转义*/
创建文本节点

document.createTextNode(插入节点的文本):注意:这些要插入的文本也会应用 HTML 或 XML 编码

 let textNode = document.createTextNode("<strong>Hello</strong> world!");

创建新文本节点后,其 ownerDocument 属性会被设置为 document。但在把这个节点添加到文档树之前,我们不会在浏览器中看到它。

以下代码创建了一个<div>元素并给它添加了一段文本消息:

 //第一步:创建一个div元素/节点
 let element = document.createElement("div");
 //第二步:创建一个文本节点
 let textNode = document.CreateTextNode("Hello World!");
 //第三步:给类为message的元素增加文本节点
 element.appendChild(textNode);
 //第四步:将元素添加到文档主体,才会显示
 document.body.appendChild(element);
规范文本节点

合并相邻文本节点:normalize()

该方法是在node节点中定义的,因此所有类型的节点都可以使用。在包含两个或多个相邻文本节点的父节点上调用 normalize()时,所有同胞文本节点会被合并为一个文本节点,这个文本节点的 nodeValue 就等于之前所有同胞节点 nodeValue 拼接在一起得到的字符串

拆分文本节点

splitText():从指定的位置拆分nodeValue,将一个文本节点拆分成两部分,拆分之后,原文本节点包含从开始到拆分点的文本,新文本节点包含后面的文本。这个方法返回新闻本。

 let element = document.createElement("div"); 
 element.className = "message"; 
 let textNode = document.createTextNode("Hello world!"); 
 element.appendChild(textNode); 
 document.body.appendChild(element); 
 let newNode = element.firstChild.splitText(5); 
 alert(element.firstChild.nodeValue); // "Hello" 
 alert(newNode.nodeValue); // " world!" 
 alert(element.childNodes.length); // 2

5、DMO编程

通过 HTML 代码能实现的,也一样能通过 JavaScript 实现。

1、动态脚本

有两种方式通过<script>动态为网页添加脚本:引入外部文件和直接插入源代码。

方法一:外部文件通过DOM编程动态创建节点

 //方法一:外部文件通过DOM编程动态创建节点
 //这是一个外部文件
 <script src="foo.js"></script>
 //创建一个元素节点,赋值给script对象
 let script = document.createElement("script");
 //给script对象加上src属性
 script.src = "foo.js";
 //将script节点加载到文档数,才会下载外部js文件
 document.body.appendChild(srcipt);
 ​
 //用函数封装
 function loadScript(url){
     let srcipt = document.creatElement("script");
     srcipt.src = url;
     document.body.appendChild(srcipt);
 }
 //动态加载
 loadSrcipt("bar.js")

方法二:1-动态插入源代码

 //这是一段srcipt代码
 <script> 
  function sayHi() { 
  alert("hi");
 }</srcipt>
 //使用DOM操作,依然可以实现:
 //第一步,创建一个srcipt节点
 let script = document.createElement("script");
 //第二步 给srcipt增加一个新的子文本节点,用于存放源码
 //源码以text的类型被增加到srcipt内部的节点中
 srcipt.appendChild(document.createTextNode("function sayHi(){alert("Hi!");}"))
 //展示
 document.body.appendChild(srcipt);
 //以上代码不支持旧版IE

2-通过<script>元素上有一个 text 属性,可以用来添加 JavaScript 代码

 var script = document.createElement("script"); 
 script.text = "function sayHi(){alert('hi');}"; 
 document.body.appendChild(script);
 //老版safari不支持,哎呦其他方式实现,了解这么多差不多啦
2、动态样式

CSS可以通过link外部引入 也可以写style嵌入样式

跟动态脚本一样,添加动态样式也可以从两方面入手

方法一:通过DOM操作动态引入CSS外部样式

 //外部文件通过DOM编程动态创建节点
 //第一步:创建一个link节点
 let link = document.createElement("link");
 //给link添加rel/type/href属性
 link.rel = "stylesheet";
 link.type = "text/css";
 link.href = "style.css";
 //获取head中的任意一元素
 let head = document.getElementByTagName("head")[0];
 //将link元素添加至获取的head元素内部
 head.appendChild(link);

函数表示为

 function loadCss(url){
     let link = document.creatElement("link");
     link.rel = "stylesheet";
     link.type = "text/css";
     link.href = url;
     let head = document.getElementByTagName("head")[0];
     head.appendChild(link);
 }
 loadCss("style.css")

方法二:动态插入源码,部分老版IE不支持

 //这是一段CSS
 <style type="text/css"> 
 body { 
  background-color: red; 
 } 
 </style>
 //通过DOM操作实现
 let style = document.createElement("style");
 style.rel = "stylesheet";
 style.type = "text/css";
 style.appendChild(document.createTextNode("body{background-color:red}")); 
 let head = document.getElementsByTagName("head")[0]; 
 head.appendChild(style);
3、操作表格

为了方便创建表格,HTML DOM 给<table><tbody><tr>

元素添加了一些属性和方法。

<table>元素添加了以下属性和方法:(表元指单元格)

  caption,指向<caption>元素的指针(如果存在);
 ​
  tBodies,包含<tbody>元素的 HTMLCollection;
 ​
  tFoot,指向<tfoot>元素(如果存在);
 ​
  tHead,指向<thead>元素(如果存在);
 ​
  rows,包含表示所有行的 HTMLCollection;
 ​
  createTHead(),创建<thead>元素,放到表格中,返回引用;
 ​
  createTFoot(),创建<tfoot>元素,放到表格中,返回引用;
 ​
  createCaption(),创建<caption>元素,放到表格中,返回引用;
 ​
  deleteTHead(),删除<thead>元素;
 ​
  deleteTFoot(),删除<tfoot>元素;
 ​
  deleteCaption(),删除<caption>元素;
 ​
  deleteRow(*pos*),删除给定位置的行;
 ​
  insertRow(*pos*),在行集合中给定位置插入一行。
 ​
 <tbody>元素添加了以下属性和方法:
 ​
  rows,包含<tbody>元素中所有行的 HTMLCollection;
 ​
  deleteRow(*pos*),删除给定位置的行;
 ​
  insertRow(*pos*),在行集合中给定位置插入一行,返回该行的引用。
 ​
 <tr>元素添加了以下属性和方法:
 ​
  cells,包含<tr>元素所有表元的 HTMLCollection;
 ​
  deleteCell(*pos*),删除给定位置的表元;
 ​
  insertCell(*pos*),在表元集合给定位置插入一个表元,返回该表元的引用。
 ​
 这些属性和方法极大地减少了创建表格所需的代码量。

案例:

 // 创建表格
 let table = document.createElement("table"); 
 table.border = 1; 
 table.width = "100%"; 
 // 创建表体
 let tbody = document.createElement("tbody"); 
 table.appendChild(tbody); 
 // 创建第一行
 tbody.insertRow(0); 
 tbody.rows[0].insertCell(0); 
 tbody.rows[0].cells[0].appendChild(document.createTextNode("Cell 1,1")); 
 tbody.rows[0].insertCell(1); 
 tbody.rows[0].cells[1].appendChild(document.createTextNode("Cell 2,1")); 
 // 创建第二行
 tbody.insertRow(1); 
 tbody.rows[1].insertCell(0); 
 tbody.rows[1].cells[0].appendChild(document.createTextNode("Cell 1,2")); 
 tbody.rows[1].insertCell(1); 
 tbody.rows[1].cells[1].appendChild(document.createTextNode("Cell 2,2")); 
 // 把表格添加到文档主体
 document.body.appendChild(table);

这里创建<table>和<tbody>元素的代码没有变。变化的是创建两行的部分,这次使用了 HTML DOM 表格的属性和方法。创建第一行时,在<tbody>元素上调用了 insertRow()方法。传入参数 0,表示把这一行放在什么位置。然后,使用 tbody.rows[0]来引用这一行,因为这一行刚刚创建并被添加到了<tbody>的位置 0。创建表元的方式也与之类似。在<tr>元素上调用 insertCell()方法,传入参数 0,表示把这个表元放在什么位置上。然后,使用 tbody.rows[0].cells[0]来引用这个表元,因为这个表元刚刚创建并被添加到了<tr>的位置 0。

6、使用NodeList

理解 NodeList 对象和相关的 NamedNodeMap、HTMLCollection,是理解 DOM 编程的关键。这3 个集合类型都是“实时的”,意味着文档结构的变化会实时地在它们身上反映出来,因此它们的值始终代表最新的状态。实际上,NodeList 就是基于 DOM 文档的实时查询。

任何时候要迭代 NodeList,最好再初始化一个变量保存当时查询时的长度,然后用循环变量与这个变量进行比较,不然容易造成无限循环

 //错误演示-无限循环-因为NodeList是实时更新的,不断的增加div,长度也会不断地增加
 let divs = document.getElementsByTagName("div"); 
 for (let i = 0; i < divs.length; ++i){ 
  let div = document.createElement("div"); 
  document.body.appendChild(div); 
 }
 //建议:
 let divs = document.getElementsByTagName("div"); 
 //初始化一个长度
 for (let i = 0, len = divs.length; i < len; ++i) { 
  let div = document.createElement("div"); 
  document.body.appendChild(div); 
 }
  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值