zoukankan      html  css  js  c++  java
  • Web APIs---4. DOM(4)

    5 节点操作

    5.1 为什么学习节点操作

    5.2 节点概述

    一般情况下,节点至少拥有节点类型(nodeType)、节点名称(nodeName)、节点值(nodeValue)这三个基本属性

    <body>
        <!-- 节点的优点 -->
        <div>我是div</div>
        <span>我是span</span>
        <ul>
            <li>我是li</li>
            <li>我是li</li>
            <li>我是li</li>
            <li>我是li</li>
        </ul>
        <div class="box">
            <span class="erweima">x</span>
        </div>
        <script>
            var box = document.querySelector('.box');
            console.dir(box); //可以通过这个方式查看节点的属性
        </script>
    </body>
    

    查看部分属性:

    • 元素节点的nodeType为1(常用)
    • 属性节点的nodeType为2
    • 文本节点的nodeType为3(包含文字空格换行等)

    5.3 节点层级

    5.3.1 父级节点

    node.parentNode//得到的是距离node最近的父级元素节点,如果找不到其父节点就返回为null
    
    <body>
        <!-- 节点的优点 -->
        <div>我是div</div>
        <span>我是span</span>
        <ul>
            <li>我是li</li>
            <li>我是li</li>
            <li>我是li</li>
            <li>我是li</li>
        </ul>
        <div class="demo">
            <div class="box">
                <span class="erweima">x</span>
            </div>
        </div>
    
        <script>
            //获取box和erweima这两个盒子
            //过去的做法
            // var erweima = document.querySelector('.erwima');
            // var box = document.querySelector('.box');
            //1. 父节点parentNode  现在的做法
            var erweima = document.querySelector('.erweima');
            console.log(erweima.parentNode); //得到的是距离元素erweima最近的父级节点box,如果找不到其父节点就返回为null
        </script>
    </body>
    

    5.3.2 子节点

    • 标准:
    parentNode.childNodes//返回包含指定节点parentNode的子节的的集合(包括元素节点、文本节点等)
    
    <body>
        <!-- 节点的优点 -->
        <div>我是div</div>
        <span>我是span</span>
        <ul>
            <li>我是li</li>
            <li>我是li</li>
            <li>我是li</li>
            <li>我是li</li>
        </ul>
        <ol>
            <li>我是li</li>
            <li>我是li</li>
            <li>我是li</li>
            <li>我是li</li>
        </ol>
        <div class="demo">
            <div class="box">
                <span class="erweima"></span>
            </div>
        </div>
        <script>
            //获取ul里面的li
            //过去的方法
            var ul = document.querySelector('ul');
            var lis = ul.querySelectorAll('li');
    
            //现在的方法
            //1. 子节点   返回包含指定节点的子节的的集合,该集合为即时更新的集合
            console.log(ul.childNodes); //NodeList(9) [text, li, text, li, text, li, text, li, text]   返回值里包含了所有的节点 包括元素节点、文本节点等  中间有5个换行,所以有5个文本节点text
    
            console.log(ul.childNodes[0].nodeType); //3    文本节点的nodeType的属性是3
            console.log(ul.childNodes[1].nodeType); //1    元素节点的nodeType的属性是1
    
            //为了获得其中的元素节点需要专门处理(所以一般不提倡用childNodes)
            for (var i = 0; i < ul.childNodes.length; i++) {
                if (ul.childNodes[i].nodeType == 1) {
                    console.log(ul.childNodes[i]);
                }
            }
        </script>
    </body>
    
    • 非标准:
    parentNode.children//可以得到所有的子元素节点  是一个只读属性  返回一个伪数组
    
    <body>
        <!-- 节点的优点 -->
        <div>我是div</div>
        <span>我是span</span>
        <ul>
            <li>我是li</li>
            <li>我是li</li>
            <li>我是li</li>
            <li>我是li</li>
        </ul>
        <ol>
            <li>我是li</li>
            <li>我是li</li>
            <li>我是li</li>
            <li>我是li</li>
        </ol>
        <div class="demo">
            <div class="box">
                <span class="erweima"></span>
            </div>
        </div>
        <script>
            //获取ul里面的li
            //过去的方法
            var ul = document.querySelector('ul');
            var lis = ul.querySelectorAll('li');
    
            //现在的方法
            //1. 子节点   返回包含指定节点的字节的的集合,该集合为即时更新的集合
            console.log(ul.childNodes); //NodeList(9) [text, li, text, li, text, li, text, li, text]   返回值里包含了所有的节点包括元素节点、文本节点等  中间有5个换行,所以有5个文本节点text
    
            console.log(ul.childNodes[0].nodeType); //3    文本节点的nodeType的属性是3
            console.log(ul.childNodes[1].nodeType); //1    元素节点的nodeType的属性是1
    
            //为了获得其中的元素节点需要专门处理(所以一般不提倡用childNodes)
            for (var i = 0; i < ul.childNodes.length; i++) {
                if (ul.childNodes[i].nodeType == 1) {
                    console.log(ul.childNodes[i]);
                }
            }
    
            //2. 获取所有的子元素节点
            console.log(ul.children); //HTMLCollection(4) [li, li, li, li]
        </script>
    </body>
    
    子节点的相关操作:获取第一个子元素和最后一个子元素
    parentNode.firstChild  //返回第一个子节点,找不到则返回null。同样也是包含所有的节点
    
    parentNode.lastChild  //返回最后一个子节点,找不到则返回null。同样也是包含所有的节点
    
    parentNode.firstElementChild  //返回第一个子节点,找不到则返回null。只包含元素节点
    
    parentNode.lastElementChild  //返回最后一个子节点,找不到则返回null。只包含元素节点
    

    注意:后两个方法有兼容性问题,ie9以上才支持

    <body>
        <ol>
            <li>我是li1</li>
            <li>我是li2</li>
            <li>我是li3</li>
            <li>我是li4</li>
        </ol>
        <script>
            var ol = document.querySelector('ol');
            //1. 不仅仅包含元素节点
            console.log(ol.firstChild); //#text    文本节点
            console.log(ol.lastChild); //#text    文本节点
    
            //2. 兼容性问题
            console.log(ol.firstElementChild); //<li>我是li1</li>
            console.log(ol.lastElementChild); //<li>我是li4</li>
    
            //3. 实际开发  既没有兼容性问题又返回第一个子元素
            console.log(ol.children[0]); //<li>我是li1</li>
            console.log(ol.children[ol.children.length - 1]); //<li>我是li4</li>
        </script>
    </body>
    
    案例:下拉菜单

    • 导航栏里面的li都要有鼠标经过的效果,所以需要循环注册鼠标事件
    • 核心原理:当鼠标经过li里面的第二个孩子(ul)显示,当鼠标离开,则ul隐藏。
    <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>
    
            <li>...</li>
            
            <li>...</li>
    
            <li>...</li>
        </ul>
    
        <script>
            //1. 获取元素
            var nav = document.querySelector('.nav');
            var lis = nav.querySelectorAll('li'); //得到4个小li
            //2. 循环注册事件
            for (var i = 0; i < lis.length - 1; i++) {
                lis[i].onmouseover = function() {
                    this.children[1].style.display = 'block';
                }
                lis[i].onmouseout = function() {
                    this.children[1].style.display = 'none';
                }
            }
        </script>
    </body>
    

    样式内容省略

    5.3.3 兄弟节点

    <body>
        <div>我是div</div>
        <span>我是span</span>
        <script>
            var div = document.querySelector('div');
            //1. node.nextSibling  返回当前元素的下一个兄弟节点,找不到则返回null。包含所有节点
            console.log(div.nextSibling); //#text
            //2. node.previousSibling 返回当前元素的上一个兄弟节点,找不到则返回null。包含所有节点
            console.log(div.previousSibling); //#text
    
            //3. node.nextElementSibling  返回当前元素的下一个兄弟元素节点,找不到则返回null。
            console.log(div.nextElementSibling); //<span>我是span</span>
            //4. node.previousElementSibling  返回当前元素的上一个兄弟元素节点,找不到则返回null。
            console.log(div.previousElementSibling); //null  因为div上面没有兄弟了
            //后两个方法依然有兼容性问题,ie9以上才支持
            //解决方法:自己封装一个函数(了解)
            function getnextElementSibling(element){
                var el = element;
                while(el = el.nextSibling) {
                    if(el.nodeType == 1) {
                        return el;
                    }
                }
                return null;
            }
        </script>
    </body>
    

    5.4 创建节点 和添加节点---->document.creatElement()、node.appendChild()、node.insertBefore()

    • 创建
    document.creatElement('tagName')//创建由tagName指定的HTML元素。因为这些元素原先不存在,是我们根据需求动态生成的,所以我们也称为动态创建元素节点。
    
    • 添加
    node.appendChild(child)//将一个节点添加到指定父节点的子节点列表的末尾。类似于css元素里的after伪元素。
    
    node.insertBefore(child,指定元素)//将一个节点添加到父节点指定子节点前面。类似于css里面的before伪元素。
    
    <body>
        <ul>
            <li>123</li>
        </ul>
        <script>
            //在ul里动态地再创建一个li
            //1. 创建元素节点
            var li = document.createElement('li');
            //2. 添加节点 node.appendChild(child)  node是父级  child是子级  在后面追加元素
            var ul = document.querySelector('ul');
            ul.appendChild(li);
    
            //1. 创建元素节点
            var lili = document.createElement('li');
            //3. 添加节点node.insertBefore(child,指定元素)
            ul.insertBefore(lili, ul.children[0]);
        </script>
    </body>
    
    

    案例:简单版发布留言案例

    • 思路: 当点击按钮之后就动态创建一个li,之后再把li创建到ul之中就可以了
    • 在创建li的同时,把文本域里面的值通过li.innerHTML赋值给li
    • 如果想要新的留言后面显示就用appendChild,如果想要前面显示就用insertBefore
    <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 {
                    //(1)创建元素
                    var li = document.createElement('li');
                    //给li赋值
                    li.innerHTML = text.value;
                    //(2)添加元素
                    // ul.appendChild(li);新留言在最前面
                    ul.insertBefore(li, ul.children[0]);
                }
    
            }
        </script>
    </body>
    

    样式省略

    5.5 删除节点---->node.removeChild()

    • 语法:
    node.removeChild(child)//从DOM中删除一个子节点,返回删除的节点
    
    • 举例:
    <body>
        <button>删除</button>
        <ul>
            <li>熊大</li>
            <li>熊二</li>
            <li>光头强</li>
        </ul>
    
        <script>
            //点击一次按钮删除一个li,到最后没有li的时候,按钮将禁用
            var btn = document.querySelector('button');
            var ul = document.querySelector('ul');
            btn.onclick = function() {
                if (ul.children.length == 0) {
                    btn.disabled = true;
                } else {
                    ul.removeChild(ul.children[0]);
                }
            }
        </script>
    </body>
    
    删除留言案例
    • 当我们把文本域里面的值赋值给li的时候,多添加一个删除连接
    • 需要把所有的链接获取过来,当点击当前的链接的时候,删除当前连接所在的li
    • 阻止连接跳转添加javascript:void(0)或者javascript:;
    <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 {
                    //(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 是a的父亲
                    var as = document.querySelectorAll('a');
                    for (var i = 0; i < as.length; i++) {
                        as[i].onclick = function() {
                            ul.removeChild(this.parentNode);//删除的是当前的a所在的li  this.parentNode
                        }
                    }
                }
    
            }
        </script>
    </body>
    
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        
        body {
            padding: 100px;
        }
        
        textarea {
             200px;
            height: 100px;
            border: 1px solid pink;
            outline: none;
            resize: none;
        }
        
        ul {
            margin-top: 50px;
        }
        
        li {
             300px;
            padding: 5px;
            background-color: rgb(245, 209, 243);
            color: red;
            font-size: 14px;
            margin: 15px 0;
        }
        
        li a {
            float: right;
            text-decoration: none;
        }
    </style>
    

    5.5 复制节点(克隆节点)

    • 语法
    node.cloneNode()//返回该方法节点的一个副本
    
    • 注意:
      (1)如果括号参数为空或者为false,则是浅拷贝,即只是克隆节点本身,不克隆节点里的子节点
      (1)如果括号参数为true,则是深拷贝,不只克隆节点本身,还克隆节点里的子节点

    • 举例

    <body>
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
        </ul>
        <script>
            var ul = document.querySelector('ul');
            //克隆节点  
            var liliq = ul.children[0].cloneNode(); //浅拷贝
            var lilis = ul.children[0].cloneNode(true); //深拷贝
            //将克隆的节点放在ul中的最末的位置
            ul.appendChild(liliq);
            ul.appendChild(lilis);
        </script>
    </body>
    

    案例:动态生成表格


    表格里的数据用对象的形式存储,因为里面既有姓名又有科目成绩
    表格分为thead和tbody,其中thead部分的内容不变,tbody的内容是js动态生成的,在js动态生成之前只有表头部分:如下:

    <body>
        <table cellspacing="0">
            <thead>
                <tr>
                    <th>姓名</th>
                    <th>科目</th>
                    <th>成绩</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
    
            </tbody>
        </table>
        <script>
            //先准备好学生数据,用数组datas存放对象
            var datas = [{
                name: '卫英络',
                subject: 'javascript',
                score: 100
            }, {
                name: '红利',
                subject: 'javascript',
                score: 98
            }, {
                name: '富恒',
                subject: 'javascript',
                score: 85
            }, {
                name: '明玉',
                subject: 'javascript',
                score: 60
            }];
    
    
    
            //往tbody里面创建行:有几个人(数组长度)就创建几行
            var tbody = document.querySelector('tbody');
            //1. 创建tr行
            for (var i = 0; i < datas.length; i++) { //外层for循环管行
                var tr = document.createElement('tr');
                tbody.appendChild(tr);
    
                //2. 在行里面创建单元格     与数据(姓名、科目、成绩)相关的单元格
                for (var k in datas[i]) { //内存for循环管每行里面创建多少个单元格,每个对象里有多少个属性就创建几个单元格
                    var td = document.createElement('td');
                    //将对象datas[i]里的属性值datas[i][k]给td
                    td.innerHTML = datas[i][k];
                    tr.appendChild(td);
                }
    
                //3. 创建删除单元格(最后一列)
                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所在的行tr(a 的父亲是td, td的父亲是tr) node.removeChild(child)
                    tbody.removeChild(this.parentNode.parentNode);
                }
            }
    
            //说明:
            // for(var k in obj) {//obj是某对象
            //     k得到的是属性名
            //     obj[k]得到的是属性值
            // }
        </script>
    </body>
    
    <style>
        table {
             500px;
            margin: 100px auto;
            border-collapse: collapse;
            text-align: center;
        }
        
        td,
        th {
            border: 1px solid #333;
        }
        
        thead tr {
            height: 40px;
            background-color: #ccc;
        }
    </style>
    

    5.6三种动态创建元素的区别---->document.write()、element.inneHTML、document.creatElement()

    • document.write()
    • element.inneHTML
    • document.creatElement()

    区别:
    (1)document.write()是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘。原先页面里面的内容就没有了

    <body>
        <button>点击</button>
        <p>abc</p>
        <script>
            //三种创建元素方式的区别
            //1. document.write() 创建元素
            var btn = document.querySelector('button');
            btn.onclick = function() { //按钮点击是在文档流执行完毕
                    document.write('<div>123</div>'); //按钮点击之后,文档里面只有内容123
                }
        </script>
    </body>
    

    (2)innerHTML是将内容写入某个DOM节点,不会导致页面全部重绘
    (3)innerHTML创建多个元素效率更高(不要拼接字符串,采取数组式拼接),但结构稍微复杂
    (4)creatElement()创建多个元素效率稍微低一点,但是结构更清晰
    总结:在不同浏览器下,创建多个标签innerHTML效率比creatElement高;创建单个标签没什么大的区别

    <body>
        <button>点击</button>
        <p>abc</p>
        <div class="inner"></div>
        <div class="create"></div>
        <script>
            //三种创建元素方式的区别
            //2. innerHTML 创建元素  创建100个a
            var inner = document.querySelector('.inner');
            for (var i = 0; i <= 100; i++) {
                inner.innerHTML += '<a href="#">百度</a>'////以拼接字符串的方式 用时很长
            }
            //3. document.createElement()创建元素   创建100个a
            var creat = document.querySelector('.create');
            for (var i = 0; i <= 100; i++) {
                var a = document.createElement('a');
                create.appendChild(a);
            }
        </script>
    </body>
    
    <body>
        <button>点击</button>
        <p>abc</p>
        <div class="inner"></div>
        <div class="create"></div>
        <script>
            //三种创建元素方式的区别
            //2. innerHTML 创建元素  创建100个a
            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()创建元素   创建100个a
            var creat = document.querySelector('.create');
            for (var i = 0; i <= 100; i++) {
                var a = document.createElement('a');
                create.appendChild(a);
            }
        </script>
    </body>
    
  • 相关阅读:
    Flink 电商实时数仓(二十三):ClickHouse基础(二)使用基础(2)ClickHouse 的安装(centos)
    Flink 电商实时数仓(二十二):ClickHouse基础(一)使用基础(1)ClickHouse 入门
    Flink 源码(二十六):Flink 内存管理(二)内存数据结构 、管理器
    Flink 源码(二十五):Flink 内存管理(一)内存模型与内存数据结构
    Flink 源码(二十四):Flink 任务调度机制(五)调度
    460. LFU Cache (solution 1)
    785. Is Graph Bipartite? (是否二分图)
    1318. Minimum Flips to Make a OR b Equal to c
    211. Add and Search Word
    188. Best Time to Buy and Sell Stock IV
  • 原文地址:https://www.cnblogs.com/deer-cen/p/12237812.html
Copyright © 2011-2022 走看看