节点(属性、层级、操作)
一、节点
HTML文档可以看作是一个节点树,网页中的所有内容都是 节点 。
1.节点的属性
(1)节点类型:nodeType
元素节点 ---1
属性节点 ---2
文本节点 ---3 (文字、空格、换行)
(2)节点名称:nodeName
(3)节点值:nodeValue
2.节点层级
在一个 HTML 文件中, 我们可以将其视为由各个 HTML 元素构成的层级结构体; 其中每个层次中的元素都按照其类型和位置形成了明确的关系.
(1)根节点:就是根节点,有且只有一个
(2)父节点:一个节点的上级节点
(3)子节点:一个节点的下级节点
(4)兄弟节点:具有相同父节点的节点
3.节点的操作
(1)获取父节点 :element.parentNode
<body>
<div class="demo">
<div class="box">
<span class="child">西安邮电大学</span>
</div>
</div>
<script>
var child = document.querySelector('.child');
console.log(child.parentNode);
</script>
</body>

(2)获取子节点
在JavaScript中存在两种方法用于获取当前元素的所有子节点:通过访问 childNodes 属性或 children 属性。
children属性具有可读性,并能遍历所有子节点。 children仅返回子元素,在实际应用中这些信息不会被包含在结果集合中。目前该属性已被广泛应用于各种编程环境中,并且在开发过程中可以通过'obj.children[索引]'的方式访问所需数据项。
调用element对象中的nodesCount属性来计算当前文档树中包含多少个直接或间接的HTML标记。
(3)获取兄弟节点
在JavaScript语言中,默认情况下可以通过 nextSibling 属性访问下一个相邻元素,并且同样地,在JavaScript中也可以通过 previousSibling 属性访问前一个相邻元素。这些方法会返回Element或Text类型的对象。若无对应元素可寻,则返回null。
后续的兄长;获取下一个兄长。
前一兄长;获取上一个兄长。
下一元素的所有兄长。
=
=
=
前一元素的所有兄长。
<body>
<div class="demo">
<div class="box">
<h2>德云</h2>
<span class="child">西安邮电大学</span>
<p>西安交通大学</p>
</div>
</div>
<div>
<ul>
<li>红楼梦</li>
<li>西游记</li>
<li>水浒传</li>
<li>三国演义</li>
</ul>
</div>
<script>
var child = document.querySelector('.child');
console.log(child.parentNode);
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
console.log(lis)
console.log("childNodes获取ul的子节点:", ul.childNodes)//九个,包括换行
console.log("children获取ul的子节点:", ul.children)//
console.log("ul的第一个子节点类型:",ul.childNodes[0].nodeType) //文本
console.log("ul的二个子节点类型:",ul.childNodes[1].nodeType) //元素 (标签)
console.log("ul的第一个子节点:",ul.firstChild);
console.log("ul的最后一个子节点:",ul.lastChild);
console.log("ul的第一个子元素节点:",ul.firstElementChild);
console.log("ul的最后一个子元素节点:",ul.lastElementChild);
var span = document.querySelector('.child');
console.log("span的下一个兄弟节点:",span.nextSibling.nextSibling)
console.log("span的上一个兄弟节点:",span.previousSibling.previousSibling)
</script>
</body>

**【案例】**下拉菜单
案例需求: 当鼠標指標經過選單時, 會展現所選選單項的內容並阻止其他子選單內容顯示。
<style>
*{
margin: 0;
padding: 0;
}
li{
list-style-type: none;
}
a{
text-decoration: none;
font-size: 14px;
}
.nav{
margin: 100px;
}
.nav>li{
position: relative;
float: left;
width: 80px;
height: 41px;
text-align: center;
}
.nav li a{
display: block;
width: 100%;
height: 100%;
line-height: 41px;
color: #333;
}
.nav>li>a:hover{
background-color: #eee;
}
.nav ul{
display: none;
position: absolute;
top: 41px;
left: 0;
width: 100%;
border-left: 1px solid #FECC5B;
border-right: 1px solid #FECC5B;
}
.nav ul li{
border-bottom: 1px solid #FECC5B;
}
.nav ul li a:hover{
background-color: #FFF5DA;
}
</style>
<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>
//1.获取外层的ul及其子元素节点
var nav = document.querySelector('.nav');
var lis = nav.children;
//2.给每个li(菜单项)绑定鼠标进入和鼠标离开的事件
for(var i=0;i<lis.length;i++){
lis[i].onmouseover = function(){
this.children[1].style.display = 'block'
}
lis[i].onmouseout = function(){
this.children[1].style.display = 'none'
}
}
</script>
</body>

(4)创建节点(动态创建节点)
在DOM环境中, 通过调用文档.createElement('tagName')的方法生成指定为tagName的HTML元素节点.
document.write()函数:在网页处于已加载状态时使用会导致网页重新渲染。
element.innerHTML属性用于将节点添加至某元素内,并可能导致部分元素重新显示。
document.createElement()用于生成节点,并有助于保持结构清晰度Aiding in creating nodes with a clear structure, but may impact performance efficiency.
(5)添加和删除节点
DOM中支持了 **node.appendChild() 和 node.insertBefore() 这两个方法来实现功能,并用 node.removeChild(child) 来删除指定的子节点。
appendChild():向指定父节点追加该子节点到其现有子节点集合的末端。
insertBefore():将该子节点插入到指定父节点现有子节点集合的最前端。
removeChild(child):移除该特定子节点。
**【案例】**简易留言板
案例分析:基于节点创建、生成和新增的相关知识来构建一个基础的留言系统功能模块。
<style>
*{
margin: 0;
padding: 0;
}
body{
padding: 100px;
}
textarea{
width: 200px;
height: 100px;
border: 1px solid pink;
outline: none;
resize: none;
}
ul{
margin-top: 50px;
}
li{
width: 300px;
padding: 5px;
background-color: #eee;
font-size: 15px;
margin: 15px 0;
}
li a{
float: right;
}
</style>
<body>
<textarea></textarea>
<button>发布</button>
<ul></ul>
<script>
//1.获取元素
var btn = document.querySelector('button');
var txt = document.querySelector('textarea');
var ul = document.querySelector('ul');
//2.按钮绑定click事件
btn.onclick = function(){
if(txt.value === ''){
alert("您没有输入内容")
}else{
//2.1 创建子元素(li)
var li = document.createElement('li');
//2.2 将文本区的内容放入li中
li.innerHTML = txt.value + "<a href='javascript:;'>删除</a>"
txt.value = ''
//2.3 将li添加到ul的最前面
ul.insertBefore(li,ul.children[0]);
//2.4 当用户点击删除时,删除ul下的li
var as = document.querySelectorAll('a');
for(var i=0;i<as.length;i++){
as[i].onclick = function(){
ul.removeChild(this.parentNode);//删除当前a标签的父节点--li
}
}
}
}
</script>
</body>

(6)复制节点(克隆节点)
在JavaScript的DOM操作中使用JavaScript API时,在支持JavaScript的对象操作环境中(如MDNWeb Docs),提供了node.cloneNode()方法。该方法返回一个新的DOM元素实例(即克隆后的副本),其内容与原始对象完全相同。语法上,“true”表示仅复制文本内容,“false”则表示包括所有子标签和属性。
true:深拷贝,复制节点本身和所有子节点
false(或空):浅拷贝,只赋值节点本身
<body>
<ul id="mylist">
<li>苹果</li>
<li>橘子</li>
<li>橙子</li>
</ul>
<ul id="op"></ul>
<button onclick="fun()">点我</button>
<script>
function fun(){
//找到mylist的第一个子节点
var item = document.getElementById('mylist').firstElementChild;
//复制子节点
var cloneItem = item.cloneNode(true);
//将复制的节点添加到op中
document.getElementById('op').appendChild(cloneItem)
}
</script>
</body>

