节点 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>

image-20210126000221092

li和li之间回车当成 文本节点 被获取过来,当然这些回车是没有啥作用的。

我们可以通过节点类型筛选一下。

children 获取子元素

这个获取子元素就不会和上面的一样把换行也获取过来了,当然获取也是子元素节点构成的数组

firstChild lastChild获取子节点

这些获取节点的方式,同样会把文本节点获取过来。这样获取的一定是空格了。

firstElementChild lastElementChild 获取 子元素节点

和字面意思一样,但是不会获取文本节点了

下拉菜单的实现

Animation1.gif

这个问题就,用节点操作就十分简单了

  • 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之间的 换行。

image-20210127163107422

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>

image-20210127170717319

非常方便。

简单实现发布留言

练习一下前面所学的创建和添加节点。

注意的点是,获取文本域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>

image-20210127173337940

删除节点

有了增加,那么删除也是必不可少的。

    <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) 深拷贝,不但复制标签,还复制标签内的内容

值得注意的是,无论深浅,标签的属性都会复制。

image-20210127200310892

    <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>

努力成长的程序员