节点 note
前面学习到了,使用DOM api获取元素,但是其实不过方便,如果已经得到了父元素,就为了获取子元素,而再去调用一大串api 函数不是很方便。
一个html页面下所有东西都可以看出一个节点
**节点获取元素:**元素之间的父子关系获取元素。
节点至少有 noteType nodeName nodeValue 三个基本属性
- 元素节点 nodeType =1 ,
- 属性节点 nodeType = 2
- 文本节点 noedeType =3 (文本节点包括 文字 换行 空格)
我们主要操作的是元素节点,文本节点和元素节点作用就非常低了。
parentNode 获取父节点
通过 Element.parentNode 获取的是里该元素最近的父节点。如果找不到就返回null
例如
<div>
<div class="son"></div>
</div>
<script>
var son=document.querySelector('.son');
var parent=son.parentNode;//获取父元素 div
</script>
childNodes 获取所有的子元素
通过Element.childNones 获取的所有子节点的所组成数组,包括文本节点(回车 空格 文字)
<ul>
<li>获取所有的li</li>
<li>获取所有的li</li>
<li>获取所有的li</li>
<li>获取所有的li</li>
<li>获取所有的li</li>
</ul>
<script>
var ul=document.querySelector('ul');
console.log(ul.childNodes);
</script>
看li和li之间回车当成 文本节点 被获取过来,当然这些回车是没有啥作用的。
我们可以通过节点类型筛选一下。
children 获取子元素
这个获取子元素就不会和上面的一样把换行也获取过来了,当然获取也是子元素节点构成的数组
firstChild lastChild获取子节点
这些获取节点的方式,同样会把文本节点获取过来。这样获取的一定是空格了。
firstElementChild lastElementChild 获取 子元素节点
和字面意思一样,但是不会获取文本节点了
下拉菜单的实现
这个问题就,用节点操作就十分简单了
- onmouseover 鼠标经过
- onmouseout 鼠标离开
我的布局如下:
每个菜单栏都是li组成,下拉菜单是,ul组成。
<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>
......
</ul>
var nav =document.querySelector('.nav');
for(var i=0;i<nav.children.length;i++)
{
nav.children[i].onmouseover=function(){
this.children[1].style.display='block';
}
nav.children[i].onmouseout=function(){
this.children[1].style.display='none';
}
}
兄弟节点
我们可以获取子节点和父节点,当然也可以获取同在一级的兄弟节点。
nextSibling 获取下一个兄弟节点
<div>我的兄弟节点是 span</div>
<span>我的兄弟节点是 div</span>
<script>
var div=document.querySelector('div');
console.log('div的兄弟节点'+div.nextSibling);
</script>
猜一下输出结果,同样,div的下一个兄弟节点是 #text
,nextSibling
是不会忽略文本节点的,也就是div和span之间的 换行。
previousSibling 上一个兄弟节点
获取下一个都有,上一个自然就不缺失啦。
和前面的一样,无法忽略 文本节点。当然如果没有的话会返回 null
nextElementSibling 和previousElementSibling
使用这两个元素就可以完全忽略文本节点啦,如果找不到就返回null
只不过,这两个ie9上才支持,不过谁现在还用ie呢
当然,为了兼容性,我们完全可以写一个函数,
function getNextSibling(element) {
var ele=element;
while (ele=ele.nextSibling) {
if (ele.nodeType==1)
return ele;
}
return null;
}
动态创建元素节点
document.createElement(el)
创建节点
我们使用createElement(el) 创建节点。但是我还得告诉浏览器这个节点放到那里去。
Element.appendChild(el)
添加到子元素
这个函数就告诉浏览器把我们前面创建的节点添加到哪里的函数
如果想添加元素,这两个函数是不可少的。
当然这个是添加到原有子元素的后面
<ul></ul>
<script>
var ul =document.querySelector('ul');
var li =document.createElement('li');
li.innerText="我是createElement('li')创建的";
ul.appendChild(li);
</script>
element.insertBefore(插入的元素,被插入的元素)
,插入子节点元素的前面
我们可以插入到后面,插入到前面的函数也是有的。
<script>
var ul =document.querySelector('ul');
var li =document.createElement('li');
li.innerText="我是createElement('li')创建的";
ul.appendChild(li);
var li1 =document.createElement('li');
li1.innerText="我要插入到前面去";
ul.insertBefore(li1,ul.children[0]);
</script>
非常方便。
简单实现发布留言
练习一下前面所学的创建和添加节点。
注意的点是,获取文本域textarea
内的文字,innerText
是获取不了的,应该获取 value的值
<div class="box">
<textarea name="" id="ly" cols="30" rows="10"></textarea><button id="fb">发布留言</button>
<ul id="lyl">
<li>我是第一条留言</li>
</ul>
</div>
<script>
var ly=document.getElementById('ly');
var lyl=document.getElementById('lyl');
var fb=document.getElementById('fb');
fb.onclick=function(){
var text=ly.value;
if(text!='')
{
var li=document.createElement('li');
lyl.appendChild(li);
li.innerText=text;
}
}
</script>
删除节点
有了增加,那么删除也是必不可少的。
<ul>
<li>删除节点1</li>
<li>删除节点2</li>
<li>删除节点3</li>
</ul>
Element.removeChild('childnode')
删除指定子节点
我写了简单的时间来删除子节点元素
var ul=document.querySelector('ul');
var button =document.querySelector('button');
button.onclick = function(){
if(ul.children.length==0)
{
button.disabled='disable';
} else{
ul.removeChild(ul.children[0]);
}
}
ul.removeChild(ul.children[0]);
删除浏览的简单实现
其实这个和前面的方法添加浏览非常相似,我们通过一个a标签当作按钮, href='javascript:;
可以让不跳转到任何页面,也不会像 #
在后面加一个井号,非常nice.我们a标签是被 留言li包起来的,可以直接删除a的父标签完成效果。
<div class="box">
<textarea name="" id="ly" cols="30" rows="10"></textarea><button id="fb">发布留言</button>
<ul id="lyl">
</ul>
</div>
<script>
var ly=document.getElementById('ly');
var lyl=document.getElementById('lyl');
var fb=document.getElementById('fb');
var as=lyl.querySelectorAll('a');
fb.onclick=function(){
var text=ly.value;
if(text!='')
{
var li=document.createElement('li');
li.innerHTML=text +"<a href='javascript:;''>删除</a>";
lyl.insertBefore(li,lyl.children[0]);
}
as=lyl.querySelectorAll('a');
for(var i=0;i<as.length;i++)
{
as[i].onclick=function(){
lyl.removeChild(this.parentNode);
}
}
}
</script>
节点的复制
Element.cloneNode()
我看可以通过这个函数复制自己,当然这个仅仅是复制自己还要告诉浏览器你要添加在哪里呢。
例如
var aClone=a.cloneNode();
li.appendChild(aClone);
深拷贝,浅拷贝
没想到把,JavaScript里也有这个概念,但是和C++的意义上是不一样的。
cloneNode(false)
这个是默认的参数,可以不写,浅拷贝,只复制标签,但是不复制标签内内容cloneNode(true)
深拷贝,不但复制标签,还复制标签内的内容
值得注意的是,无论深浅,标签的属性都会复制。
<div class="box">我爱你</div>
<script>
var box =document.querySelector('.box');
var qbox =box.cloneNode(true);
var hbox =box.cloneNode();
console.log(qbox);
console.log(hbox);
</script>