一文吃透JavaScript中的DOM知识及用法
Posted Java Fans
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文吃透JavaScript中的DOM知识及用法相关的知识,希望对你有一定的参考价值。
文章目录
一、前言
DOM:Document Object Model(文档对象模型),定义了用户操作文档对象的接口,可以说DOM是自html将网上相关文档连接起来后最伟大的创新。它使得用户对HTML有了空前的访问能力,并使开发者将HTML作为XML文档来处理。
本文知识导图如下:
二、DOM框架
DOM是网页的核心结构,无论是HTML、CSS还是javascript,都和DOM 密切相关。HTML的作用是构建DOM结构,CSS的作用是设定样式,JavaScript的作用是读取以及控制、修改DOM。
当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。
如下面一段HTML代码可以用 HTML DOM 树来表示:
代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>window</title>
</head>
<body>
<h2><a href="#">标题文本</a></h2>
<p>段落文本</p>
<ul class="ul_Web">
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
</body>
</html>
HTML DOM 树
在这个树状图中,html位于位于最顶端,它没有父辈,也没有兄弟,被称为DOM的根节点。更深入一层会发现,html有head和body两个分支,它们在同一层而不相互包含,它们之间是兄弟关系,有着共同的父元素html。再往深会发现head有两个子元素meta和title,它们互为兄弟。而body有三个子元素,分别是h2、p和ul。再继续深入还会发现h2和ul都有自己的子元素。
通过这样的关系划分,整个HTML文件的结构清晰可见,各元素之间的关系很容易表达出来,这正是DOM所实现的。
通过可编程的对象模型,JavaScript 获得了足够的能力来创建动态的 HTML。
- JavaScript 能够改变页面中的所有 HTML 元素
- JavaScript 能够改变页面中的所有 HTML 属性
- JavaScript 能够改变页面中的所有 CSS 样式
- JavaScript 能够对页面中的所有事件做出反应
三、认识DOM节点
节点(node)最初源于计算机网络中,代表着网络中的一个连接点,可以说网络就是由节点构成的集合。DOM节点也是类似,文档是由节点构成的集合。
在DOM中有3种节点,分别是元素节点、文本节点和属性节点。
元素节点:可以说整个DOM都是由元素节点构成的,如:html、body、meta、h2、p、li等都是元素节点。元素节点可以包含其他的元素(除了html根元素)。
文本节点:在HTML中光有元素节点搭建的框架是不够的,页面开发的最终目的是向用户展示内容。例如li元素中含有的文本信息,每个li之间的换行操作都是文本节点。并不是所有的元素节点中都含有文本节点。
如下例:p元素中直接包含元素节点,无文本节点。
<p><span></span></p>
属性节点:作为页面中的元素,或多或少会有一些属性,如下面例子中,含有了,class、title、color等属性。开发者可以利用这些属性来对包含在元素里的对象作出更准确的描述。
例子:
<a class="a_css" title="CSS" color="#0F0" href="#">进入CSS网站</a>
由于属性总是被放在元素里,因此属性节点总是被包含在元素节点中。
上例中可以看出各种节点的关系如下图:
四、JS访问DOM
每个DOM节点都有一系列的属性、方法可以使用。下表中总结了常用的节点属性和方法,供使用时快速查阅。
属性/方法 | 类型/返回类型 | 说明 |
---|---|---|
nodeName | String | 节点名称,根据节点的类型而定义 |
nodeValue | String | 节点的值,同样根据节点的类型而定义 |
nodeType | Number | 节点类型 |
firstChild | Node | 指向childNodes列表中的第一个节点 |
lastChild | Node | 指向childNodes列表中的最后一个节点 |
childNodes | NodeList | 所有子节点的列表,方法item(i)可以访问第i+1个节点 |
parentNode | Node | 指向节点的父节点,如果该节点已是根节点,则返回null |
previousSibling | Node | 指向节点的前一个兄弟节点,如果该节点已是第一个节点,则返回null |
nextSibling | Node | 指向节点的后一个兄弟节点,如果该节点已是最后一个节点,则返回null |
hasChildNodes | Boolean | 当childNodes包含一个或多个节点时,返回true |
attributes | NameNodeMap | 包含一个元素特征的Attr对象,仅用于元素节点 |
appendChild | Node | 将node节点添加到childNodes的末尾 |
removeChild | Node | 从childNodes中删除node节点 |
replaceChild | Node | 将childNodes中的oldnode节点替换成newnode节点 |
insetBefore | Node | 在childNodes中的refnode节点之前插入newnode节点 |
1、获取节点
- document.getElementById【通过id属性获取对象】
因为id具有唯一性,所以通过该方法获取的html元素只有一个。 - document.getElementsByTagName【通过标签名获取对象】
获取的元素有一个或者多个,将获取的元素存储在一个类似数组的集合中,获取的元素通过下标来区分(下标从0开始) - document.getElementsByClassName【通过class属性获取对象】
不同的标签可以使用同一个class属性值,所以获取的元素由一个或者多个,获取的元素存储在一个类似数组的集合中,获取的元素通过下标来区分(下标从0开始) - querySelector【根据id、标签、class名获取元素】
不管是哪一个名称,都获取第一个元素 - querySelectorAll【获取所有执行标签名/带有指定class名的元素】
案例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>dom操作</title>
</head>
<body>
<h2>登鹳雀楼</h2>
<p id="test">白日依山尽,</p>
<p>黄河入海流。</p>
<p class="demo">欲穷千里目,</p>
<p>更上一层楼。</p>
<div class="demo">div标签1</div>
<div>div标签2</div>
</body>
<script>
//获取html元素
//getElementById('id属性值'):通过标签的id属性来获取元素,因为id具有唯一性,所以通过该方法获取的html元素只有一个
var ele =document.getElementById('test');
console.log(ele);
// ele.style.color = '#f00';
console.log('--------------------');
//getElementsByTagName('标签名'):通过标签名称获取元素,获取的元素由一个或者多个,将获取的元素存储在一个类似数组的集合中,获取的元素通过下标来区分(下标从0开始)
var pEles=document.getElementsByTagName('p');
console.log(pEles);
console.log(pEles[2]);
console.log('获取的p元素个数:'+pEles.length);
console.log('--------------------');
//getElementsByClassName('class属性值'):通过标签的class属性值来获取元素,不同的标签可以使用同一个class属性值,所以获取的元素由一个或者多个,获取的元素存储在一个类似数组的集合中
var elements =document.getElementsByClassName('demo');
console.log(elements);
//querySelector('id名/标签名/class名'):根据id、标签、class名获取元素,不管是哪一个名称,都获取第一个元素
var result1 =document.querySelector('#test');
console.log(result1);
var result2 = document.querySelector('.demo');
console.log(result2);
var result3 =document.querySelector('p');
console.log(result3);
console.log('--------------------');
//querySelectorAll('标签名/class名'):获取所有执行标签名/带有指定class名的元素
var demoEles=document.querySelectorAll('.demo');
console.log(demoEles);
var pElemets = document.querySelectorAll('p');
console.log(pElemets);
</script>
</html>
2、改变 HTML
语法 | 说明 |
---|---|
document.write() | 改变 HTML 输出流 |
对象.innerHTML=新的 HTML | 改变 HTML 内容(包含元素、属性、文本) |
对象.innerText=文本内容 | 改变HTML文本内容 |
对象.attribute=新属性值 | 改变 HTML 属性 |
例1:document.write()应用
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>write()</title>
<style>
.ddd
color: #00f;
background-color: #ccc;
</style>
</head>
<body>
大湖名城,创新高地2
<button onclick="show()">点我一下</button>
</body>
<script>
document.write('<br />大湖名城,创新高地<br />');
document.write('<h2>二级标题标签</h2>')
document.write('<p style="color:#f00;">段落标签</p>')
document.write('<p class="ddd">段落标签2</p>');
function show()
document.write('hello js!');
</script>
</html>
运行效果:
例2:innerHTML和innerText应用
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>innertHTML和innerText</title>
</head>
<body>
<ul>
<li>列表项第一项</li>
<li>列表项第二项</li>
</ul>
<div></div>
</body>
<script>
//获取ul元素
var ulEle =document.querySelector('ul');
ulEle.innerHTML = '<li>大湖名城,创新高地</li>';
var result1 =ulEle.innerHTML;
console.log(result1);
var result2 =ulEle.innerText;
console.log(result2);
//获取div标签
var divEle = document.querySelector('div');
divEle.innerText = '<h2>大湖名城,创新高地</h2>';
</script>
</html>
运行效果:
例3:通过改变img固有属性值实现两张图片切换
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>改变和获取标签固有属性值</title>
</head>
<body>
<img src="img/lyf.jpg" width="300px"/>
<button onclick="changeImg()">换一张图片</button>
</body>
<script>
//获取img标签
var imgEle = document.querySelector('img');
var flag = true;
function changeImg()
if(flag)
imgEle.src='img/wzx.jpg';
imgEle.style.width='500px';
flag=false;
else
imgEle.src='img/lyf.jpg';
imgEle.style.width='300px';
flag=true;
</script>
</html>
运行效果:
3、改变 CSS
通过JavaScript改变CSS样式的思路:先获取需要改变样式的元素,可通过document.querySelector()方法获取。然后再通过上图语法中的方法去改变元素的样式。
案例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>改变元素的样式</title>
</head>
<body>
<p class="demo">大湖名城,创新高地</p>
<button onclick="addCss()">给P标签添加样式</button>
</body>
<script>
//获取p标签
var pEle = document.querySelector('p');
function addCss()
pEle.style.color= '#f00';
pEle.style.backgroundColor = '#ccc';
pEle.style.fontSize = '30px';
pEle.style.textDecoration='underline';
</script>
</html>
运行效果:
4、检测节点类型
通过节点的nodeType属性可以检测出节点的类型。该属性返回一个代表节点类型的整数值,总共有12个可取的值,例如:
console.log(document.nodeType);
上面代码执行后的返回值为9,表示DOCUMENT_NODE类型节点。然而实际上,对于大多数情况而言,真这行游泳的还是前面我们学过的3种节点,即元素节点、文本节点和属性节点,他们的nodeType值如下:
-
元素节点
- nodeType值为1 属性节点
- nodeType值为2 文本节点
- nodeType值为3
这就意味着可以对某种类型的节点做单独的处理,在搜索节点的时候非常实用。
5、操作节点间的父子及兄弟关系
【1】通过父节点找到子节点
父子兄弟关系是DOM模型中节点之间非常重要的关系,在获取某个节点之后,可以通过父子关系,利用hasChildNodes()方法和childNodes属性获取该节点所包含的所有子节点。
案例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<ul>
<li>Java</li>
<li>Node.js</li>
<li>JavaScript</li>
</ul>
</body>
<script>
//获取ul标记
var ulEle=document.querySelector("ul");
var DOMString="";
if(ulEle.hasChildNodes())
for (var s of ulEle.childNodes)
DOMString+=s.nodeName+"\\n";
console.log(DOMString);
</script>
</html>
这个案例的首先获取ul标记,然后利用hasChildNodes()判断其是否有子节点,如果有则利用childNodes遍历它的所有子节点。执行后控制台输出结果可以看到ul包括4个文本节点和3个元素节点。
运行效果:
除了获取全部子节点,DOM还提供了firstChild和lastChild两个属性,分别表示获取父元素的第一个子元素和最后一个子元素。
案例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<ul>
<li>Java</li>
<li>Node.js</li>
<li>JavaScript</li>
</ul>
</body>
<script>
//获取ul标记
var ulEle = document.querySelector('ul');
//获取ul的Javascript之DOM的三大节点及部分用法
DOM有三种节点:元素节点、属性节点、文本节点。
一、用nodeType可以检测节点的类型
节点类型
nodeType属性值
元素节点
1
属性节点
2
文本节点
3
这样方便在js中对各个节点进行操作。
元素节点:html中的标签。
属性节点:html便签中的属性值。
文本节点:元素节点之间的文本。
二、用body的childNodes来测试
1 <body>/*第一个文本元素
2 */<div></div>/*第二个文本元素
3 */<div></div>/*第三个文本元素
4 */<ul>
5 <li></li>
6 <li></li>
7 <li></li>
8 </ul>/*第四个文本元素
9 */</body>
来看body的childNodes中各个节点的个数。
先说一下childNodes,这个属性用来获取任何一个元素的所有子元素,它是一个包含这个元素的全部子元素的数组。
用js测试:
1 window.onload = function (){
2 var oBody = document.getElementsByTagName(‘body‘)[0];
3 var aChild = oBody.childNodes;
4 alert(aChild.length);//7
5 for(var i = 0; i < aChild.length; i++) {
6 alert(aChild[i].nodeType);//3 1 3 1 3 1 3
7 }
8 };
由此看来:
body的子元素有div、div、ul。
body的文本元素有四个,代码中注释出出来的,我故意将*/换了一行写出来,是想表明在<body>和<div>之间是一个文本节点。
有人会觉得疑惑,不是说元素节点之间就是文本节点吗?为什么像<div></div>之间的文本节点没有算进去呢?
对的,那个也算文本节点,但我们计算的是body的子节点,像<div></div>之间的那是<div>的子节点啦,并不是body的子节点。
三、用nodeValue来得到和设置一个节点的值
三大节点中,属性节点和文本节点都是可能有值的,但是元素节点是没有值的。
用node.nodeValue得到node的值,那么有一个问题,nodeValue和innerHTML有什么区别呢?
nodeValue获取的是节点的值,innerHTML是以字符串形式返回该节点的所有子节点及其值。可以看做是部分与大体的一个区别。
举个例子:
1 <body>
2 <div id="div1">
3 这是div的第一个子节点,是一个文本节点
4 <p>div的第二个子节点p,这是p的第一个文本节点</p>
5 </div>
6 </body>
我们用js来测试一下nodeValue和innerHTML的结果
1 window.onload = function (){
2 var oDiv = document.getElementById(‘div1‘);
3 var aChild = oDiv.childNodes;
4
5 alert(aChild[0].nodeValue);
6 alert(oDiv.innerHTML);
7 };
测试结果如下:
第一个alert弹出“这是div的第一个子节点,是一个文本节点”
第二个alert弹出“这是div的第一个子节点,是一个文本节点 <p>div的第二个子节点p,这是p的第一个文本节点</p>”
三、用nodeName来获取节点的
nodeName属性含有某个节点的名称。
对于元素节点,nodeName=标签名(返回的名称是大写的)。
对于文本节点,nodeName=#text。
对于属性节点,nodeName=属性名(返回的名称是大写的)。
使用方法:elemt.nodeName;
以上是关于一文吃透JavaScript中的DOM知识及用法的主要内容,如果未能解决你的问题,请参考以下文章