节点操作
因为利用DOM提供的方法获取元素逻辑性不强且非常繁琐
因此学习利用节点层级关系获取元素:
利用父子兄的关系获取元素
逻辑性强,但兼容性差
节点:页面中所有的内容都是节点(标签,属性,文本,注释等),在DOM中,节点使用node来获取
HTML DOM树中的所有节点都可以通过JS来访问,所有HTML元素都可以被修改,也可以创建或者删除
节点至少有:nodeType(节点类型)、nodeName(节点名称)、nodeValue(节点值)这三个基本属性
元素节点 nodeType 为 1
属性节点 nodeType 为 2
文本节点 nodeType 为 3 (文本节点包含 文字、空格、换行等)
在实际开发中,主要操作的是元素节点
父节点 parentNode
<body>
<div class="box">
<span class="erweima"></span>
</div>
<script>
//1.父节点 parentNode
var erweima = document.querySelector('.erweima');
//以往得到box节点
var box = document.querySelector('box');
console.log(erweima.parentNode); //通过erweima的父节点得到box节点
</script>
得到的是离元素最近的父节点(就近原则),如果找不到父节点,就返回为空(null)
子节点 childNodes
以此为例:
<ol>
<li></li>
<li></li>
<li></li>
</ol>
<ul>
<li></li>
<li></li>
<li></li>
</ul>
1. 方法一:
element.childNodes :这样得到的是所有的子节点,包括 元素节点、文本节点等
如果只想要获得里面的元素节点,还需要做出一些处理ul.childNodes[i].nodeType == 1
元素节点 nodeType 为 1、属性节点 nodeType 为 2、文本节点 nodeType 为 3
//2.子节点
var ul = document.querySelector("ul");
console.log(ul.childNodes); //这样得到的是所有的子节点,包括 元素节点、文本节点等
//如果只想要获得里面的元素节点,还需要做出一些处理
for (var i = 0; i < ul.childNodes; i++) {
for (var i = 0; i < ul.childNodes; i++) {
//ul.childNodes[i] 是元素节点
console.log(ul.childNodes[i]);
}
}
但上述方法较为麻烦。不常用
2. 方法二
children 获取所有的子元素节点 是常用的开发技术
//children 获取所有的子元素节点 是常用的开发技术
console.log(ul.children);
firstChild 返回第一个子节点,无论是文本节点还是元素节点
lastChild 返回最后一个子节点,无论是文本节点还是元素节点
firstElementChild 返回第一个子元素节点 ie9才支持(存在兼容性问题)
console.log(ol.firstChild);
console.log(ol.lastChild);
console.log(ol.firstElementChild);
特殊地:如果想获得第i个子元
素的方法为:element.children[i]
//特殊地:如果想获得第i个子元素的方法为:element.children[i]
var ol = document.querySelector("ol");
console.log(ol.children[0]); //获得第一个元素
console.log(ol.children[ol.children.length - 1]); //获得最后一个元素
案例一: 下拉菜单
分析:导航栏里面的li都要有鼠标经过效果,所以需要循环注册鼠标事件
核心原理:当鼠标经过li里面的 第二个孩子 ul 显示,当鼠标离开 则ul隐藏
代码:
<style>
* {
padding: 0;
margin: 0;
}
li {
list-style-type: none;
}
a {
text-decoration: none;
}
.nav {
margin: 100px auto;
width: 400px;
}
.nav > li {
position: relative;
display: inline-block;
height: 41px;
line-height: 41px;
text-align: center;
height: 41px;
width: 80px;
}
.nav > li:hover {
background-color: #eee;
}
.nav ul {
display: none; /*初始时下来菜单隐藏起来*/
position: absolute;
top: 41px;
left: 0;
width: 100%;
}
.nav ul li {
display: block;
margin: 0 -2.5px 0px -2.5px;
border-left: 1px solid #fecc58;
border-right: 1px solid #fecc58;
border-bottom: 1px solid #fecc58;
}
.nav ul li:hover {
background-color: #fff5da;
}
</style>
</head>
<body>
<ul class="nav">
<li>
<a href="#">微博</a>
<ul>
<li><a herf="#">关注</a></li>
<li><a herf="#">关注</a></li>
<li><a herf="#">关注</a></li>
</ul>
</li>
<li>
....
</li>重复
</ul>
<script>
//分析:导航栏里面的li都要有鼠标经过效果,所以需要循环注册鼠标事件
//核心原理:当鼠标经过li里面的 第二个孩子 ul 显示,当鼠标离开 则ul隐藏
var nav = document.querySelector(".nav");
var lis = nav.children; //得到四个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>
兄弟节点
node.nextSibling 得到的是下一个兄弟节点,包括元素节点或者文本节点,找不到则返回空
node.previousSibling 得到的是上一个兄弟节点,包括元素节点或者文本节点,找不到则返回空
nextElementSibling 得到的是下一个兄弟元素节点(存在兼容性问题 ie9以上支持)
previousElementSibling 得到的是上一个兄弟节点 (存在兼容性问题 ie9以上支持)
<body>
<div>div</div>
<span>span</span>
<script>
var div = document.querySelector("div");
//nextSibling 得到的是下一个兄弟节点,包括元素节点或者文本节点,找不到则返回空
console.log(div.nextSibling); //返回 span 的元素节点
//previousSibling 得到的是上一个兄弟节点,包括元素节点或者文本节点,找不到则返回空
console.log(div.previousSibling); //返回 null
//nextElementSibling 得到的是下一个兄弟元素节点(存在兼容性问题 ie9以上支持)
console.log(div.nextElementSiblinshang);
//previousElementSibling 得到的是上一个兄弟节点 (存在兼容性问题 ie9以上支持)
console.log(div.previousElementSibling);
</script>
</body>
可以通过自己封装一个兼容性的函数来解决不兼容的问题
//可以通过自己封装一个兼容性的函数
function getextElementSibling(element) {
var el = element;
while ((el = el.nextSibling)) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
创建/添加节点
1.创建节点
document.creatElement('target') node 是被创建的节点,此方法创建由 tagName 指定的 HTML 元素 。因为这些元素原先并不存在,是根据我们的需求动态生成的,因此也称为动态创建元素节点
2. 添加节点
(1)node.appendChild(child) node是父节点 child 是子节点 ,将一个节点添加到指定父节点的子节点列表末尾(追加元素)在后面添加,类似于css里面的after伪元素
(2)node.insertBefore(child,指定元素) 在指定元素前面添加,
<body>
<ul></ul>
<script>
//1.创建节点 createElement("node") node 是被创建的节点
var li = document.createElement("li");
//2.添加节点 node.appendChild(child)
// node是父节点 child 是子节点
//将一个节点添加到指定父节点的子节点列表末尾
//(追加元素)后面添加
var ul = document.querySelector("ul");
ul.appendChild(li);
//node.insertBefore(child,指定元素)
//在指定元素前面添加
var lili = document.createElement('li');
ul.insertBefore(lili,ul.children[0]);
</script>
</body>
我们想在页面中添加一个新的元素,分为两步:
1.创建元素 2.添加元素
案例二:简单版发布留言
案例分析:
核心思路:点击按钮之后,就动态创建一个li,添加到ul里面
创建li的同时,把文本域里面的值通过li.innerHTML赋值给li
如果想要新的留言在后面显示就用appendChild ,如果想要在前面显示就用insertBefore
<body>
<textarea name="" id=""></textarea>
<button>发布</button>
<ul></ul>
<script>
var btn = document.querySelector("button");
var text = document.querySelector("textarea");
var ul = document.querySelector("ul");
btn.onclick = function () {
if (text.value == null) {
alert("您没有输入内容");
} else {
//创建元素
var li = document.createElement("li");
//把文本域的值传递给新创建的节点
li.innerHTML = text.value;
//添加元素
ul.appendChild(li); //新的放在后面
ul.insertBefore(li, ul.children[0]); //新的放在前面
}
};
</script>
</body>