一、DOM基本概念
1. DOM基本概念
- DOM是JS操控HTML和CSS的桥梁。
- DOM是JS操作HTML变得优雅。
DOM(Document Object Model,文档对象模型)
是JavaScript操作HTML文档的接口,使文档操作变得非常优雅、简便。- DOM最大的特点就是将文档表示为节点树。
- 节点的
nodeType
属性可以显示这个节点具体的类型。nodeType值 节点类型 1
元素节点,例如 <p>
和<div>
3
文字节点 8
注释节点 9
document节点 10
DTD节点
二、节点访问和位置关系
1. 访问元素节点
- 所谓"访问"元素节点,就是指"得到"、"获取"页面上的元素节点。
- 对节点进行操作,第一步就是要得到它。
- 访问元素节点主要依靠
document
对象。
认识
document
对象document
对象是DOM
中最重要的东西,几乎所有DOM的功能都封装在了document对象中
.document
对象也表示整个HTML文档
,它是DOM
节点树的根。document
对象的nodeType属性值是9
。
访问元素节点的常用方法
方法 功能 兼容性 document.getElementById()
通过 id
得到元素IE6 document.getElementByTagName()
通过 标签名
得到元素数组IE6 document.getElementByClassName()
通过 类名
得到元素数组IE9 document.querySelector()
通过 选择器
得到元素IE8部分兼容 IE9完全兼容 document.querySelectorAll()
通过 选择器
得到元素数组IE8部分兼容 IE9完全兼容 document.getElementById()
功能是通过id得到元素节点
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script> // 给window对象添加onload事件监听。onload表示页面都加载完毕了。 window.onload = function () { // 得到盒子1 var box1 = document.getElementById('box1'); // 得到盒子2 var box2 = document.getElementById('box2'); console.log(box1); console.log(box2); }; </script> </head> <body> <div id="box1">我是盒子1</div> <div id="box2">我是盒子2</div> </body> </html>
- 参数就是元素节点的id,注意
不要写#号
通常JS代码一定要写到HTML节点的后面
,否则JS无法找到相应HTML节点。- 可以使用
window.onload = function(){}
事件,使页面加载完毕后,再执行指定的代码。 - 如果页面上
有相同id的元素,则只能得到第一个
- 不管元素藏的位置有多深,都能通过id把它找到。
- 参数就是元素节点的id,注意
document.getElementByTagName()
功能是通过标签名得到节点数组。
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="box1"> <p>我是段落</p> <p>我是段落</p> <p>我是段落</p> <p>我是段落</p> </div> <div id="box2"> <p>我是段落</p> <p>我是段落</p> <p>我是段落</p> <p>我是段落</p> </div> <script> // 先得到box1 var box1 = document.getElementById('box1'); // 得到box1中的p标签的数组 var ps_inbox1 = box1.getElementsByTagName('p'); console.log(ps_inbox1); </script> </body> </html>
- 数组方便遍历,从而可以
批量操控元素节点
- 即使页面只有一个指定标签名的节点,也将得到
长度为1的数组
任何一个节点元素也可以调用getElementsByTagName()方法
,从而得到其内部的某种类的元素节点。
- 数组方便遍历,从而可以
document.getElementByClassName()
功能是通过类名得到节点数组
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div class="spec"> <p>我是段落</p> <p>我是段落</p> <p>我是段落</p> <p>我是段落</p> </div> <div class="spec"> <p>我是段落</p> <p>我是段落</p> <p>我是段落</p> <p>我是段落</p> </div> <script> // box var box = document.getElementsByClassName('spec'); console.log(box); </script> </body> </html>
- 注意不要写
.
号 document.getElementByClassName()
方法从IE9开始兼容
。某个节点元素也可以调用document.getElementByClassName()方法
,从而得到其他内部的某类名的元素节点。
- 注意不要写
querySelector()
方法的功能是通过选择器得到元素html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="box1"> <p class="spec">我是段落</p> <p>我是段落</p> <p>我是段落</p> <p>我是段落</p> </div> <script> var p = document.querySelector('#box1 .spec'); console.log(p); </script> </body> </html>
querySelector()
方法只能得到页面上一个元素
,如果有多个元素符合条件,则只能得到第一个元素。querySelector()
方法从IE8开始兼容,但从IE9开始支持CSS3的选择器
,但从IE9开始支持CSS3的选择器
, 如:nth-child()
、:[src^='dog']
等CSS3选择器形式都支持良好。
querySelectorAll()
方法的功能是通过选择器得到元素数组
。- 即使页面上只有一个符合选择器的节点,也将得到长度为
1
的数组
- 即使页面上只有一个符合选择器的节点,也将得到长度为
2. 节点的关系
关系 | 考虑所有节点 |
---|---|
子节点 | childNodes |
父节点 | parentNodes |
第一个子节点 | fristChild |
最后一个子节点 | lastChild |
前一个兄弟节点 | previousSibling |
后一个兄弟节点 | nextSibling |
DOM中,文本节点也属于节点,在使用节点的关系时一定要注意
在标准的W3C规范中,空白文本节点也应该算作节点
,但是在IE8及以前的浏览器会有一定的兼容问题,它们不把空白文本节点当做节点。排除文本节点的干扰,从IE9开始支持一些"只考虑元素节点"的属性
关系 考虑所有节点 只考虑元素节点 子节点
childNodes
children
父节点
parentNodes
children
第一个子节点
fristChild
fristElementChild
最后一个子节点
lastChild
lastElementChild
前一个兄弟节点
previousSibling
previousElementSibling
后一个兄弟节点
nextSibling
nextElementSibling
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="box"> <p>我是段落A</p> <p id="para">我是段落B</p> <p>我是段落C</p> </div> <script> var box = document.getElementById('box'); var para = document.getElementById('para'); // 所有子节点 console.log(box.childNodes); // 所有的元素子节点(IE9开始兼容) console.log(box.children); // 第一个子节点 console.log(box.firstChild); console.log(box.firstChild.nodeType); // 第一个元素子节点(IE9开始兼容) console.log(box.firstElementChild); // 最后一个子节点 console.log(box.lastChild); console.log(box.lastChild.nodeType); // 最后一个元素子节点(IE9开始兼容) console.log(box.lastElementChild); // 父节点 console.log(para.parentNode); // 前一个兄弟节点 console.log(para.previousSibling); // 前一个元素兄弟节点(IE9开始兼容) console.log(para.previousElementSibling); // 后一个兄弟节点 console.log(para.nextSibling); // 后一个元素兄弟节点(IE9开始兼容) console.log(para.nextElementSibling); </script> </body> </html>
IE6也能兼容的"寻找所有元素子节点"函数
IE6也能兼容的"寻找前一个元素兄弟节点"函数
获取某元素的所有兄弟节点
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="box"> <p>我是段落</p> <p>我是段落</p> <p>我是段落</p> <p id="fpara">我是段落fpara</p> 我是文本 <!-- 我是注释 --> <p id="para"> 我是段落para <span>1</span> <span>2</span> <span>3</span> </p> <p>我是段落</p> <p>我是段落</p> <p>我是段落</p> </div> <script> var box = document.getElementById('box'); var para = document.getElementById('para'); var fpara = document.getElementById('fpara'); // 封装一个函数,这个函数可以返回元素的所有子元素节点(兼容到IE6),类似children的功能 function getChildren(node) { // 结果数组 var children = []; // 遍历node这个节点的所有子节点,判断每一个子节点的nodeType属性是不是1 // 如果是1,就推入结果数组 for (var i = 0; i < node.childNodes.length; i++) { if (node.childNodes[i].nodeType == 1) { children.push(node.childNodes[i]); } } return children; } console.log(getChildren(box)); console.log(getChildren(para)); // 封装一个函数,这个函数可以返回元素的前一个元素兄弟节点(兼容到IE6),类似previousElementSibling的功能 function getElementPrevSibling(node) { var o = node; // 使用while语句 while (o.previousSibling != null) { if (o.previousSibling.nodeType == 1) { // 结束循环,找到了 return o.previousSibling; } // 让o成为它的前一个节点,就有点“递归”的感觉 o = o.previousSibling; } return null; } console.log(getElementPrevSibling(para)); console.log(getElementPrevSibling(fpara)); // 封装第三个函数,这个函数可以返回元素的所有元素兄弟节点 function getAllElementSibling(node) { // 前面的元素兄弟节点 var prevs = []; // 后面的元素兄弟节点 var nexts = []; var o = node; // 遍历node的前面的节点 while(o.previousSibling != null) { if(o.previousSibling.nodeType == 1){ prevs.unshift(o.previousSibling); } o = o.previousSibling; } o = node; // 遍历node的后面的节点 while(o.nextSibling != null) { if(o.nextSibling.nodeType == 1){ nexts.push(o.nextSibling); } o = o.nextSibling; } // 将两个数组进行合并,然后返回 return prevs.concat(nexts); } console.log(getAllElementSibling(para)); </script> </body> </html>
三、节点操作
1. 节点操作
如何改变元素节点中的内容
- 改变元素节点中的内容可以使用两个相关的属性:
- innerHTML
- innerText
- innerHTML属性能
以HTML语法
设置节点中的内容。 - innerText属性只能
以单纯文本的形式
设置节点中的内容。html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="box"></div> <script> var oBox = document.getElementById('box'); oBox.innerHTML = '张三'; oBox.innerHTML = '<ul><li>牛奶</li><li>咖啡</li></ul>'; </script> </body> </html>
- 改变元素节点中的内容可以使用两个相关的属性:
如何改变元素节点的CSS样式
- 改变元素节点的CSS样式需要使用这样的语句html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .box{ width: 200px; height: 200px; border: 1px solid #000; } </style> </head> <body> <div class="box" id="box"> 你好 </div> <script> var oBox = document.getElementById('box'); // oBox.style.backgroundColor = 'rgb(100, 200, 123)'; // oBox.style.backgroundColor = '#f80'; // oBox.style.backgroundImage = 'url(https://www.imooc.com/static/img/index/logo-recommended.png)'; // oBox.style.backgroundSize = 'contain'; oBox.style.fontSize = '50px'; </script> </body> </html>
- 改变元素节点的CSS样式需要使用这样的语句
如何改变元素节点的HTML属性
标准W3C属性,如src、href等等,只需要直接打点进行更改即可
不符合W3C标准的属性,要使用
setAttribute()
和getAttribute()
来设置、读取html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <img src="images/1.jpg" id="pic"> <a href="http://www.baidu.com" id="link"> 去百度 </a> <script> var oPic = document.getElementById('pic'); var oLink = document.getElementById('link'); oPic.src = 'images/2.jpg'; oLink.href = 'http://www.baidu.com'; oLink.innerText = '去百度'; </script> </body> </html>
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="box"></div> <script> var box = document.getElementById('box'); box.setAttribute('data-n', 10); var n = box.getAttribute('data-n'); alert(n); </script> </body> </html>
2. 节点创建
document.createElement()
方法用于创建一个指定tagName
的HTML元素孤儿节点
- 新创建的节点是"孤儿节点",这意味着它
并没有被挂载到DOM树上
,我们无法看到它。 - 必须继续使用
appendChild()
或者insertBefore()
方法将孤儿节点插入到DOM树上。
- 新创建的节点是"孤儿节点",这意味着它
appendChild()
方法- 任何已经在DOM树上的节点,都可以调用
appendChild()
方法,它可以将孤儿节点挂载到它的内部,成为它的最后一个子节点
- 任何已经在DOM树上的节点,都可以调用
insertBefore()
方法- 任何已经在DOM树上的节点,都可以调用insertBefore()方法,它可以将孤儿节点挂载到它的内部,成为它的"标杆子节点"之前的节点
3. 移动节点
- 如果将已经挂载到DOM树上的节点成为
appendChild()
或者insertBefore()
的参数,这个节点将会被移动 - 这意味着一个节点不能同时位于DOM树的两个位置
4. 删除节点
removeChild()
方法从DOM中删除一个子节点- 节点不能主动删除自己,必须由父节点删除它
5. 克隆节点
cloneNode()
方法可以克隆节点,克隆出的节点是"孤儿节点"- 参数是一个布尔值,表示
是否采用深度克隆
:如果为true,则该节点的所有后代节点也都会被克隆,如果为false,则只克 隆该节点本身