DOM(三)
一、节点基础
1、节点:一个页面就是一个节点树,页面中的内容就是节点
一般来说,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这3个基本属性
(1)节点类型(nodeType)
- 1表示为元素节点(即标签)
- 2表示为属性节点(标签的属性)
- 3表示为文本节点(标签的内容)
(2)节点名称(nodeName)
(3)节点值(nodeValue)
2、节点层级
一个HTML文件可以看作是所有元素组成的一个节点树,各元素节点之间有级别的划分
DOM根据HTML中各节点的不同作用,可将其分别划分为标签节点(元素节点)、文本节点和属性节点。节点之间的层级关系如下 - 根节点:标签是整个文档的根节点,有且仅有一个
- 父节点:指的是某一个节点的上级节点
- 子节点:指的是某一个节点的下级节点
- 兄弟节点:两个节点同属于一个父节点
3、获取节点
(1)获取父节点:在JavaScript中,可以使用parentNode属性来获得离当前元素的最近的一个父节点,如果找不到父节点就返回为 null,语法格式为:obj.parentNode,obj是一个DOM对象
<body>
<div class="demo">
<div class="box"><span class="child">span元素</span></div>
</div>
<script>
var child = document.querySelector('.child'); // 获取类名为child的span元素
console.log(child.parentNode); // 输出离child元素最近的父级节点(box)
</script>
</body>
(2)获取子节点:在JavaScript中,可以使用childNodes属性或者children属性两种方式来获得当前元素的所有子节点的集合
①方式1:childNodes属性获得的是当前元素的所有子节点的集合,该集合为即时更新的集合,返回的节点包括元素、文本和其他节点
②方式2:children是一个可读的属性,返回所有子元素节点。children只返回子元素节点,其余节点不返回,目前各大浏览器都支持该属性,在实际开发中推荐使用children
注:childNodes属性返回的是NodeList对象的集合,返回值里面包含了元素节点、文本节点等其他类型的节点
childNodes属性与children属性虽然都可以获取某元素的子元素,但是两者之间有一定的区别。前者用于节点操作,返回值是NodeList对象集合,后者用于元素操作,返回的是HTMLCollection对象集合
③使用firstChild属性和lastChild属性获取子节点,前者返回第一个子节点,后者返回的是最后一个子节点,如果找不到则返回null。需要注意的是它们的返回值包括文本节点和元素节点等
④使用firstElementChild属性和lastElementChild属性获取子元素节点,前者返回第一个子元素节点,后者返回最后一个子元素节点,如果找不到则返回null。需要注意的是,这两个属性有兼容性问题,IE9以上才支持
注:实际开发中,firstChild 和lastChild 包含其他节点,操作不方便,而firstElementChild和lastElementChild又有兼容性问题,为了解决兼容性问题,在实际开发中通常使用“obj.children[索引] ”的方式来获取子元素节点
<body>
<ul>
<li>li-1</li>
<li>li-1</li>
<li>li-1</li>
<li>li-1</li>
<li>li-1</li>
</ul>
<script>
var ul = document.querySelector('ul')
var lis = document.querySelectorAll('li')
console.log(lis)
console.log(ul.childNodes)
console.log(ul.childNodes[0].nodeType)
console.log(ul.childNodes[1].nodeType)
console.log(ul.children) //建议使用
console.log(ul.firstChild) //输出ul的第一个子节点
console.log(ul.firstElementChild)
console.log(ul.children[0])
</script>
</body>
obj.children[0] // 获取第一个子元素节点
obj.children[obj.children.length - 1] // 获取最后一个子元素节点
(3)获取兄弟节点
- nextSibling属性:返回后一个兄弟节点,返回值包含元素节点或者文本节点等
- previousSibling属性:返回前一个兄弟节点,返回值包含元素节点或者文本节点等
- nextElementSibling属性:返回下一个兄弟元素
- previousElementSibling属性:返回前一个兄弟元素
注:实际开发中,nextSibling和previousSibling属性返回值都包含其他节点,操作不方便,而nextElementSibling和previousElementSibling又有兼容性问题。为了解决兼容性问题,在实际开发中通常使用封装函数来处理兼容性
4、案例:下拉菜单
案例需求:鼠标指针经过菜单时,显示当前下拉框中的内容同时隐藏其他下拉菜单内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="../css/menu.css">
</head>
<body>
<ul class="nav">
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="#">私信</a>
</li>
<li>
<a href="#">评论</a>
</li>
<li>
<a href="#">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">留言板</a>
<ul>
<li>
<a href="#">私信</a>
</li>
<li>
<a href="#">评论</a>
</li>
<li>
<a href="#">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">电话</a>
<ul>
<li>
<a href="#">私信</a>
</li>
<li>
<a href="#">评论</a>
</li>
<li>
<a href="#">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">邮箱</a>
<ul>
<li>
<a href="#">私信</a>
</li>
<li>
<a href="#">评论</a>
</li>
<li>
<a href="#">@我</a>
</li>
</ul>
</li>
</ul>
<script src="../js/menu.js"></script>
</body>
</html>
二、节点的操作
1、节点的创建
在DOM中,使用document.createElement(‘tagName’)方法创建由tagName指定的HTML元素,也称为动态创建元素节点
动态创建元素节点的3种常见方式如下
-
document.write()创建元素,如果页面文档流加载完毕,再调用会导致页面重绘
-
element.innerHTML将内容写入某个DOM节点,不会导致页面全部重绘
-
document.createElement()创建多个元素效率稍微低一点,但是结构更加清晰
2、添加节点
DOM中,提供了node.appendChild()和node.insertBefore()方法用于添加节点 -
appendChild()方法,将一个节点添加到指定父节点的子节点列表末尾
-
insertBefore(child, 指定元素)方法,将一个节点添加到父节点的指定子节点前面
3、删除节点
DOM中,提供了node. removeChild(child)用于删除节点 -
removeChild(child)用于删除节点,该方法从DOM中删除一个子节点,返回删除的节点
案例:简易留言板
案例分析:利用节点的创建、添加和删除相关知识完成一个简易的留言板功能。在页面中实现单击“发布”按钮动态创建一个li元素,添加到ul里面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../html/b.css">
</head>
<body>
<textarea name="" id=""></textarea>
<button>发布微博</button>
<ul></ul>
<script>
//1、获取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea')
var ul = document.querySelector('ul')
//2、注册事件
btn.onclick = function(){
if(text.value == ''){
alert('您没有输入内容');
return false;
}else{
//a、创建元素
var li = document.createElement('li');
li.innerHTML = text.value +'<a href = "javascript:;">删除</a>'; //javascript:的意思是点击删除之后页面不刷新
//b、添加元素
ul.insertBefore(li,ul.children[0]);
var as = document.querySelectorAll('a');
for(var i = 0;i < as.length;i++){
as[i].onclick = function(){
ul.removeChild(this.parentNode);
}
}
}
}
</script>
</body>
</html>
4、复制节点
在DOM中,提供了node.cloneNode(deep)方法,返回调用该方法的节点的一个副本,也称为克隆节点或者拷贝节点
deep是逻辑值
- true表示深拷贝,即复制当前节点及其所有子节点(默认值)
- false表示浅拷贝,只复制当前节点不复制其子节点
<body>
<select id="sex">
<option>请选择</option>
<option value="1">男</option>
<option value="0">女</option>
</select>
<br><br>
<hr>
<div id="d1"></div>
<br><br>
<button type="button" onclick="copyNode(false)">浅拷贝</button>
<button type="button" onclick="copyNode(true)">深拷贝</button>
<script>
function copyNode(bool){
//获取select标签
var gender = document.querySelector('#sex')
//将select标签进行复制
var newSex = gender.cloneNode(bool)
//将select标签的副本放入div中
var mydiv = document.querySelector('#d1')
mydiv.appendChild(newSex)
}
</script>
</body>
5、插入节点
inserBefore(new,ref),将new节点插入到ref节点之前
<body>
<h3 id="h">长安大学</h3>
<form name="frm">
输入文本:<input type="text" name="txt">
<!-- <input type="button" value="插入节点" onclick="insertNode('h',document.frm.txt.value)"> -->
<button type="button">插入节点</button>
</form>
<script>
var btn = document.querySelector('button')
btn.onclick = insertNode
function insertNode(){
// var h3 = document.querySelector('#h3')
var str = document.querySelector('input').value
//创建一个p标签
var newNode = document.createElement('p')
//创建一个文本节点
var newTxt = document.createTextNode(str)
//将文本节点插入到到p标签中
newNode.appendChild(newTxt)
//找到要插入的位置(找到id属性值为nodeid的标签)
var ref = document.querySelector('#h')
//判断ref节点是否有父节点
if(ref.parentNode){
ref.parentNode.insertBefore(newNode,ref)
}
}
// var btn = document.querySelector('button')
// var va = document.querySelector('input').value
// btn.onclick = insertNode
</script>
</body>