1.6. 节点操作
1.6.1. 节点概述
定义:网页中的所有内容都是节点(标签、属性、文本、注释等),在DOM 中,节点使用 node 来表示。
注意:HTML DOM 树中的所有节点均可通过 JavaScript 进行访问,所有 HTML 元素(节点)均可被修改,也可以创建或删除。
一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。
1.6.2. 节点层级
利用 DOM 树可以把节点划分为不同的层级关系,常见的是父子兄层级关系。
1.6.3. 父级节点
<div class="demo">
<div class="box">
<span class="erweima">×</span>
</div>
</div>
<script>
// 1. 父节点 parentNode
var erweima = document.querySelector('.erweima');
// var box = document.querySelector('.box');
// 得到的是离元素最近的父级节点(亲爸爸) 如果找不到父节点就返回为 null
console.log(erweima.parentNode);
</script>
1.6.4. 子节点
所有子节点
注意:这个方法会包含text文本节点
子元素节点
<ul>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<script>
// DOM 提供的方法(API)获取
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
// 1. 子节点 childNodes 所有的子节点 包含 元素节点 文本节点(空格也算)等等
console.log(ul.childNodes);
console.log(ul.childNodes[0].nodeType);
//输出结果是3
console.log(ul.childNodes[1].nodeType);
//输出结果是1
// 2. children 获取所有的子元素节点 也是我们实际开发常用的 文本节点的nodeType是3
//元素节点的nodeType是1
console.log(ul.children);
//children可以获取所有的子元素节点 重要!
</script>
输出的结果:
第1个子节点
不管是文本节点还是文本节点都获取到
最后1个子节点
第1个子元素节点
只获取第一个子元素节点 不获取换行空格
最后1个子元素节点
总结:实际开发中,firstChild 和 lastChild 包含其他节点,操作不方便,而 firstElementChild 和 lastElementChild 又有兼容性问题,那么我们如何获取第一个子元素节点或最后一个子元素节点呢?
记住 parentNode.children[0]和parentNode.children[parentNode.children.length - 1]
<ol>
<li>我是li1</li>
<li>我是li2</li>
<li>我是li3</li>
<li>我是li4</li>
<li>我是li5</li>
</ol>
<script>
var ol = document.querySelector('ol');
// 1. firstChild 第一个子节点 不管是文本节点还是元素节点
console.log(ol.firstChild);
console.log(ol.lastChild);
// 2. firstElementChild 返回第一个子元素节点 ie9才支持
console.log(ol.firstElementChild);
console.log(ol.lastElementChild);
// 3. 实际开发的写法 既没有兼容性问题又返回第一个子元素
console.log(ol.children[0]);
console.log(ol.children[ol.children.length - 1]);
</script>
1.6.5. 案例:新浪下拉菜单
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
list-style: none;
}
.tn-person-r .tn-title {
float: left;
font-size: 14px;
position: relative;
margin-left: 20px;
width: 80px;
}
.tn-person-r .tn-title .tn-tab {
border: 1px solid #FCFCFC;
border-width: 0 1px;
color: #4C4C4C;
display: inline-block;
cursor: pointer;
position: relative;
z-index: 9999;
padding: 0 2px 0 0;
text-decoration: none;
width: 76px;
height: 40px;
line-height: 40px;
text-align: center;
}
.tn-person-r .tn-arrow {
display: inline-block;
width: 8px;
height: 5px;
margin: 0 0 0 5px;
overflow: hidden;
vertical-align: middle;
font-size: 12px;
line-height: 13px;
-webkit-transform: none;
-moz-transform: none;
-o-transform: none;
background: url(icon.png) 0 -977px no-repeat;
}
.tn-person-r .tn-new {
margin-top: -10px;
position: absolute;
background: url(icon.png) 0 -1017px;
width: 14px;
height: 11px;
}
.tn-person-r .tn-topmenulist-a-weibo,
.tn-topmenulist-a-other {
width: 77px;
}
.tn-person-r .tn-topmenulist-a {
border: 1px solid #EBBE7A;
border-top: 0;
overflow: hidden;
-moz-box-shadow: 3px 3px 3px rgba(0, 0, 0, .1);
-webkit-box-shadow: 3px 3px 3px rgba(0, 0, 0, .1);
box-shadow: 3px 3px 3px rgba(0, 0, 0, .1);
top: 41px;
left: 0;
}
.tn-person-r .tn-topmenulist .tn-text-list {
border-bottom: 1px solid #FECC5B;
margin: 0 0 -2px;
width: 80px;
}
.tn-person-r .tn-topmenulist .tn-text-list li {
width: 50px;
line-height: 31px;
border-bottom: 1px solid #FECC5B;
color: #333;
padding: 0 15px;
}
</style>
</head>
<body>
<div class="top-nav">
<div class="tn-bg">
<div class="tn-header">
<div class="tn-person-r">
<div class="tn-title " id="SI_Top_Weibo">
<a target="_blank" href="javascript:;" class="tn-tab" id="weibo">
<i>微博<em class="tn-new" style="display:none;"></em>
<span class="tn-arrow"> </span>
</i>
</a>
<div style="display: none;" class="tn-topmenulist tn-topmenulist-a tn-topmenulist-a-weibo" id="weibo_list">
<ul class="tn-text-list">
<li>私信</li>
<li>评论</li>
<li>@我</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var Top_Weibo = document.getElementById('SI_Top_Weibo');
var weibo = document.getElementById('weibo');
var weibo_list = document.getElementById('weibo_list');
var lis = document.querySelectorAll('li');
Top_Weibo.onmouseover = function() {
weibo.style.backgroundColor = '#ccc';
weibo_list.style.display = 'block';
}
Top_Weibo.onmouseout = function() {
weibo.style.backgroundColor = '';
weibo_list.style.display = 'none';
}
weibo.onmouseover = function() {
this.style.color = '#ff8400';
}
weibo.onmouseout = function() {
this.style.color = '#4c4c4c';
}
for (var i = 0; i < lis.length; i++) {
lis[i].onmouseover = function() {
this.style.color = '#ff8400';
this.style.backgroundColor = '#fff5da';
}
lis[i].onmouseout = function() {
this.style.color = '#4c4c4c';
this.style.backgroundColor = '';
}
}
</script>
</body>
</html>
1.6.6. 兄弟节点
下一个兄弟节点
<body>
<div>我是div</div>
<span>我是span<span>
<script>
var div = document.querySelector('div');
console.log(div.nextSibling)
</script>
1.nextSibling 下一个兄弟节点 包含元素节点或者 文本节点等等
上一个兄弟节点
- node.nextSibling:
node.nextSibling返回当前元素的下一个兄弟节点,找不到则返回null,同样,也是包含所有的节点 - node.previousSibling
<span>我是span<span>
<script>
var div = document.querySelector('div');
//node.nextSibling下一个兄弟节点 包含元素节点 或者文本节点等
console.log(div.node.nextSibling);
console.log(div.node.previousSibling)
</script>
上一个节点
<div>我是div</div>
<span>我是span</span>
<script>
var div = document.querySelector('div');
// 1.nextSibling 下一个兄弟节点 包含元素节点或者 文本节点等等
console.log(div.nextSibling);
console.log(div.previousSibling);
// 2. nextElementSibling 得到下一个兄弟元素节点
console.log(div.nextElementSibling);
console.log(div.previousElementSibling);
</script>
下一个兄弟元素节点(有兼容性问题)
- 兄弟节点:
- node.nextElementSibling
- 返回当前元素下一个兄弟元素节点,找不到返回null
上一个兄弟元素节点(有兼容性问题)
- node.previousElementSibling
- 返回当前元素上一个兄弟节点,找不到就返回null
但是,上面方法有兼容性。
封装一个兼容性函数来解决:
function getNextElementSibling(element) {
var el = element;
while (el = el.nextSibling) {
//获取所有节点
if (el.nodeType === 1) {
//元素节点 就把元素返回
return el;
}
}
return null;
}
1.6.7. 创建节点
1.6.8. 添加节点
<ul>
<li>123</li>
</ul>
<script>
// 1. 创建节点元素节点
var li = document.createElement('li');
// 2. 添加节点 node.appendChild(child) node 父级 child 是子级 后面追加元素
var ul = document.querySelector('ul');
//ul添加一个节点 后面追加元素 类似数组的push
ul.appendChild(li);
// 3. 添加节点 node.insertBefore(child, 指定元素); 会插入这个元素的前面
var lili = document.createElement('li');
//ul插入一个节点 在ul第一个孩子插入
ul.insertBefore(lili, ul.children[0]);
// 4. 我们想要页面添加一个新的元素 : 1. 创建元素 2. 添加元素
</script>
1.6.8.1删除节点
- node.removeChild()
- node.removeChild() 方法从 node节点中删除一个子节点,返回删除的节点。
- 代码
<button>删除</button>
<ul>
<li>熊大</li>
<li>熊二</li>
<li>光头强</li>
</ul>
<script>
// 1.获取元素
var ul = document.querySelector('ul');
var btn = document.querySelector('button');
// 2. 删除元素 node.removeChild(child)
// ul.removeChild(ul.children[0]);
// 3. 点击按钮依次删除里面的孩子
btn.onclick = function() {
//如果没得删的时候 把按钮禁用
if (ul.children.length == 0) {
//按钮禁用
this.disabled = true;
//点击就删除一个ul的第一个孩子
} else {
ul.removeChild(ul.children[0]);
}
}
</script>
1.6.9. 案例:简单版发布留言
<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 {
// console.log(text.value);
// (1) 创建元素
var li = document.createElement('li');
// 先有li 才能赋值 文本域的值给了空的li
li.innerHTML = text.value;
// (2) 添加元素
// ul.appendChild(li);
ul.insertBefore(li, ul.children[0]);
}
}
</script>
</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 {
// console.log(text.value);
// (1) 创建元素
var li = document.createElement('li');
// 先有li 才能赋值 也就是文本域+删除链接这个组合的值 赋值给li
li.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
// (2) 添加元素 文本域+删除链接 javascript:;可阻止链接跳转
// ul.appendChild(li);
ul.insertBefore(li, ul.children[0]);
// (3) 删除元素 删除的是当前链接的li 它的父亲
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
// 删除的是 li 当前a所在的li this.parentNode;
ul.removeChild(this.parentNode);
}
}
}
}
</script>
复制(克隆)节点:
案例:动态生成表格:
<script>
// 1.先去准备好学生的数据
var datas = [{
name: '魏璎珞',
subject: 'JavaScript',
score: 100
}, {
name: '弘历',
subject: 'JavaScript',
score: 98
}, {
name: '傅恒',
subject: 'JavaScript',
score: 99
}, {
name: '明玉',
subject: 'JavaScript',
score: 88
}, {
name: '大猪蹄子',
subject: 'JavaScript',
score: 0
}];
// 2. 往tbody 里面创建行: 有几个人(通过数组的长度)我们就创建几行
var tbody = document.querySelector('tbody');
// 遍历数组
for (var i = 0; i < datas.length; i++) {
// 1. 创建 tr行
var tr = document.createElement('tr');
tbody.appendChild(tr);
// 2. 行里面创建单元格td 单元格的数量取决于每个对象里面的属性个数
// 使用for in遍历学生对象
for (var k in datas[i]) {
// 创建单元格
var td = document.createElement('td');
// 把对象里面的属性值 datas[i][k] 给 td
td.innerHTML = datas[i][k];
tr.appendChild(td);
}
// 3. 创建有删除2个字的单元格
var td = document.createElement('td');
td.innerHTML = '<a href="javascript:;">删除 </a>';
tr.appendChild(td);
}
// 4. 删除操作 开始
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
// 点击a 删除 当前a 所在的行(链接的爸爸的爸爸) node.removeChild(child)
tbody.removeChild(this.parentNode.parentNode)
}
}
</script>
DOM的核心总结:
1.2.1. 创建
1.2.2. 增加
1.2.3. 删
1.2.4. 改
1.2.5. 查
1.2.6. 属性操作