节点操作、节点层次、节点的创建、添加、删除、复制,简单版发布留言案例,删除留言案例,动态生成表格案例,三种动态创建元素区别

2.4为什么学节点操作

获取元素通常使用两种方式:


Snipaste_2020-06-25_11-53-56.png

两种方式都可以获取元素节点,我们后面都会使用,但是节点操作更简单。

2.4.1节点概述

网页中的所有内容都是节点(标签、属性、文本、注释等),在DOM中,节点使用node来表示。
一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。

  • 元素节点 nodeType为1
  • 属性节点 nodeType为2
  • 文本节点 nodeType为3(文本节点包含文字、空格、换行等)
    在我们实际开发中,节点操作主要操作的是元素节点
2.4.2节点层次

利用DOM树可以把节点划分为不同的层级关系,常见的是父子兄层关系。

Snipaste_2020-06-25_12-09-41.png

1、父级节点
node.parentNode

  • parentNode属性可返回某节点的父节点,注意是最近的的一个父节点
  • 如果指定的节点没有父节点则返回null
    <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>

2、子节点
parentNode.childNodes (标准)
返回包含指定节点的子节点的集合,该集合为及时更新的集合
注意:返回值里面包含了所有的子节点,包括元素节点,文本节点等。
如果只想要获得里面的元素节点,则需要专门处理,所有我们一般不提倡使用childNodes。
parentNode.children(非标准)
parentNode.children是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回(这个是我们重点掌握的,也是我们实际开发常用的)。(虽然children是一个非标准,但是得到了各个浏览器的支持,因此我们可以放心使用。)
parentNode.firstChild
返回第一个子节点,找不到则返回null。同样也是包含所有的节点
parentNode.lastChild
返回最后节点,找不到则返回null。同样也是包含所有的节点
parentNode.firstElementChild
返回第一个子元素节点
parentNode.lastElementChild
返回最后一个子元素节点
注意:.firstElementChild .lastElementChild这两个方法有兼容问题,IE9以上才支持。
实际开发的写法,既没有兼容性问题又返回第一个子元素以及最后一个元素
原因:children返回的是一个数组的集合

console.log(ol.children[0]);
        console.log(ol.children[ol.children.length - 1]);

3、兄弟节点
node.nextSibling
返回当前元素的下一个兄弟节点,找不到返回null。同样也是包含所有节点。
node.previousSibling
返回当前元素的上一个兄弟节点,找不到则返回null。同样也是包含所有节点。
node.nextElementSibling
返回当前元素下一个兄弟元素节点,找不到则返回null
node.previousElementSibling
返回当前元素的上一个兄弟元素节点,找不到则返回null
同样nextElementSibling和previousElementSibling只支持ie9以上

###2.5下拉菜单的案例
![Snipaste_2020-06-25_13-03-55.png](https://upload-images.jianshu.io/upload_images/23083822-f3ae07d5e4c9e1a9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
```css
  <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>
 <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. 获取元素
        var nav = document.querySelector('.nav');
        var lis = nav.children; // 得到4个小li
        // 2.循环注册事件
        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>
2.4.3创建节点

document.createElement('tagName')
document.createElement()方法创建由tagName指定的HTML元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称为动态创建元素节点。

2.4.4添加节点

node.appendChild(child)
node.appendChild()方法将一个节点添加到指定父节点的子节点列表末尾。类似于css里面的after伪元素。 node是父级,child是子级。
node.insertBefore(child,指定元素)
node.insertBefore()方法将一个节点添加到父节点的指定子节点前面。类似于css里面的before伪元素。

 <ul>
        <li>123</li>
    </ul>
    <script>
        // 1. 创建节点元素节点
        var li = document.createElement('li');
        // 2. 添加节点 node.appendChild(child)  node 父级  child 是子级 后面追加元素  类似于数组中的push
        var ul = document.querySelector('ul');
        ul.appendChild(li);
        // 3. 添加节点 node.insertBefore(child, 指定元素);
        var lili = document.createElement('li');
        ul.insertBefore(lili, ul.children[0]);
        // 4. 我们想要页面添加一个新的元素 : 1. 创建元素 2. 添加元素
    </script>

2.6简单版发布留言案例

Snipaste_2020-06-25_16-41-54.png
 <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: rgb(245, 209, 243);
            color: red;
            font-size: 14px;
            margin: 15px 0;
        }
    </style>
   <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.innerHTML = text.value;
                // (2) 添加元素
                // ul.appendChild(li);
                ul.insertBefore(li, ul.children[0]);
            }
        }
    </script>
2.4.5删除节点

node.removeChild(child)
node.removeChild()方法从DOM中删除一个子节点,返回删除的节点。

<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;
            } else {
                ul.removeChild(ul.children[0]);
            }
        }
    </script>

2.7删除留言案例

Snipaste_2020-06-25_17-03-37.png
  <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: rgb(245, 209, 243);
           color: red;
           font-size: 14px;
           margin: 15px 0;
       }
       
       li a {
           float: right;
       }
   </style>
  <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.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
                // (2) 添加元素
                // 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() {
                        // node.removeChild(child); 删除的是 li 当前a所在的li  this.parentNode;
                        ul.removeChild(this.parentNode);
                    }
                }
            }
        }
    </script>
2.4.6复制节点(克隆节点)

node.cloneNode()
返回调用该方法的节点的一个副本。也称为克隆节点/拷贝节点

 <ul>
        <li>1111</li>
        <li>2</li>
        <li>3</li>
    </ul>
    <script>
        var ul = document.querySelector('ul');
        // 1. node.cloneNode(); 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容
        // 2. node.cloneNode(true); 括号为true 深拷贝 复制标签复制里面的内容
        var lili = ul.children[0].cloneNode(true);
        ul.appendChild(lili);
    </script>
2.4.7动态生成表格案例
Snipaste_2020-07-08_14-13-38.png

Snipaste_2020-07-08_15-03-31.png
  <style>
        table {
            width: 500px;
            margin: 100px auto;
            border-collapse: collapse;
            text-align: center;
        }
        
        td,
        th {
            border: 1px solid #333;
        }
        
        thead tr {
            height: 40px;
            background-color: #ccc;
        }
    </style>
  <table cellspacing='0'>
        <thead>
            <tr>
                <th>姓名</th>
                <th>科目</th>
                <th>成绩</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            
        </tbody>
    </table>
    <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++) { // 外面的for循环管行 tr
            // 1. 创建 tr行
            var tr = document.createElement('tr');
            //2、添加tr到tbody中
            tbody.appendChild(tr);
            //3、行里面添加单元格td(跟数据有关系的三个单元格) 数量取决于每个对象的个数 for循环遍历对象
            for(var k in datas[i]){//里面的循环管的是td
            //创建单元格
               var td=document.createElement('td');
                //把td加入到tr中
                tr.appendChild(td);
                //把对象里面的属性值 datas[i][k]给td
                td.innerHTML=datas[i][k];
            }
            //4、创建有删除两个字的单元格
            var td=document.createElement('td');
            tr.appendChild(td);
            //在td中添加删除
            td.innerHTML='<a href="javascript:;"> 删除</a>';
             // for(var k in obj) {
             //     k 得到的是属性名
             //     obj[k] 得到是属性值
             // }
    }
        var as=document.querySelectorAll('a');
        for(var i=0; i < as.length;i++){
            as[i].onclick=function(){
                //点击a 删除当前 a所在的行(连接的爸爸的爸爸的行) node.removeChild(child)
                //行的爸爸叫tbody
                tbody.removeChild(this.parentNode.parentNode)
            }
        }

    </script>
2.4.8三种动态创建元素区别
  • document.write() 冷门,一般不怎么使用
  • element.innerHTML
  • document.createElement()
<button>点击</button>
    <p>abc</p>
    <div class="inner"></div>
    <div class="create"></div>
    <script>
        // window.onload = function() {
        //         document.write('<div>123</div>');

        //     }
        // 三种创建元素方式区别 
        // 1. document.write() 创建元素  如果页面文档流加载完毕,再调用这句话会导致页面重绘
        // var btn = document.querySelector('button');
        // btn.onclick = function() {
        //     document.write('<div>123</div>');
        // }

        // 2. innerHTML 创建元素
        var inner = document.querySelector('.inner');
        // for (var i = 0; i <= 100; i++) {
        //     inner.innerHTML += '<a href="#">百度</a>'
        // }
        var arr = [];
        for (var i = 0; i <= 100; i++) {
            arr.push('<a href="#">百度</a>');
        }
        inner.innerHTML = arr.join('');
        // 3. document.createElement() 创建元素
        var create = document.querySelector('.create');
        for (var i = 0; i <= 100; i++) {
            var a = document.createElement('a');
            create.appendChild(a);
        }
    </script>

区别
1、document.write 是直接将内容写入页面的内容流,但文档流执行完毕,则它会导致页面全部重绘。
2、innerHTML是将内容写入某个DOM节点,不会导致页面全部重绘
3、innerTHML创建多个元素效率更高(不要拼接字符串,采用数组形式拼接),结构稍微复杂
4、creatElement()创建多个元素效率稍微低一点点,但是结构更清晰。
总结:不管在什么浏览器下,innerHTML效率都要比creatElement高

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343