DOM--node operation

We know that DOM mainly adds, deletes, modifies, and binds events to elements, so it is particularly important to obtain elements as a prerequisite.

important. There are usually two ways to get elements :

(1) Use the methods provided by DOM to obtain elements (2) Use node hierarchical relationships to obtain elements

The method provided by DOM has been introduced in the previous article, which is document.getElementById()

document.getElementsByTagName(), document.querySelector, etc. These methods are actually not very logical.

And it is relatively cumbersome.

Therefore, this article will introduce the second way - using node relationships to obtain elements and perform node operations.

1. Node Overview

All content in a web page is a node (label, attribute, text, comment, etc.). In the DOM, nodes are represented by node .
All nodes in the HTML DOM tree (shown below) can be accessed through JavaScript, and all HTML elements (nodes) can be modified, created or deleted.

Generally, nodes have at least three basic attributes:  nodeType (node ​​type), nodeName (node ​​name) and nodeValue (node ​​value) .

①The element node nodeType is 1
②The attribute node nodeType is 2
③The text node nodeType is 3 (text nodes include text, spaces, line breaks, etc.)
In our actual development, node operations mainly operate on element nodes .

2. Node level

The DOM tree can be used to divide nodes into different hierarchical relationships. The most common one is the parent-child-brother hierarchical relationship

2.1. Parent node

node.parentNode  或 node.parentElement

The parentNode attribute/ parentElement attribute has the same usage. There is no difference. Both can return the parent node of a node. Note that it is the nearest parent node.
② If the specified node has no parent node, null will be returned.  

2.2 Child nodes 

1. parentNode.childNodes

parentNode.childNodes returns a collection containing all child nodes of the specified node. This collection is an immediately updated collection.
Note: The return value contains all child nodes , including element nodes, text nodes, etc. Therefore, if you only want to get the element nodes inside, you need to handle it specially. Therefore, we generally do not advocate the use of childNodes .

2. parentNode.children

parentNode.children is a read-only property that returns all child element nodes . It only returns child element nodes, and other nodes are not returned (this is what we focus on).

3. parentNode.firstChild

4. parentNode.lastChild

firstChild returns the first child node, or null if not found. Similarly, it also contains all nodes, that is, text nodeslastChild returns the last child node, or null if not found. Likewise, all nodes are included .

5. parentNode.firstElementChild 

6. parentNode.lastElementChild

 firstElementChild returns the first child element node , or null if not found. lastElementChild returns the last child element node , or null if not found. However, these two methods have compatibility issues and are only supported by IE9 and above.

In actual development , firstChild and lastChild contain other nodes, which is inconvenient to operate, and firstElementChild and 
lastElementChild have compatibility issues. So how do we get the first child element node or the last child element node ?
Solution:
1. If you want the first child element node , you can use parentNode.chilren[0] 
2. If you want the last child element node , you can use parentNode.chilren[parentNode.chilren.length - 1] .

2.3 Case: drop-down menu

<!-- css样式 -->
<style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    body {
        background-color: #F5F5F5;
    }
    li {
        list-style: none;
    }
    #select {
        height: 50px;
        margin: 50px;
        background-color: #eee;
    }
    #select>li {
        float: left;
        width: 100px;
        height: 50px;
        line-height: 50px;
        text-indent: 5px;
    }
    a {
        color: #666;
        text-decoration: none;
    }
    a:hover {
        color: #F83C3D;
    }
    #select ul {
        display: none;
        font-size: 14px;
        width: 100px;
        background-color: #fff;
    }
</style>
<body>
    <ul id="select">
        <li>
            <a href="#">我的淘宝</a>
            <ul>
                <li>已买到的宝贝</li>
                <li>我的足迹</li>
            </ul>
        </li>
        <li>
            <a href="#">我的收藏</a>
            <ul>
                <li>收藏的宝贝</li>
                <li>收藏的店铺</li>
                <li>收藏的主播</li>
            </ul>
        </li>
        <li>
            <a href="#">联系客服</a>
            <ul>
                <li>卖家客服</li>
                <li>消费者客服</li>
                <li>意见反馈</li>
            </ul>
        </li>
    </ul>
    <script>
        // 1. 获取元素
        let lis = document.querySelectorAll("#select>li");
        // 2. 通过遍历给每个li绑定鼠标移入移出事件
        for (let i = 0; i < lis.length; i++) {
            lis[i].onmouseover = function() {
              // 鼠标移入该li背景色变成白色
                this.style.backgroundColor = '#fff';
             // 对应的下拉菜单显示(下拉菜单是该li 的第二个孩子,下标从0开始)
                lis[i].children[1].style.display = 'block';
            };
            lis[i].onmouseout = function() {
              // 鼠标移出该li背景色变回原来颜色
                this.style.backgroundColor = '';
                // 对应的下拉菜单隐藏
                lis[i].children[1].style.display = 'none';
            }
        }
    </script>
</body>

case analysis: 

① The li in the navigation bar must have a mouse passing effect, so it is necessary to register mouse events cyclically
② Core principle: When the mouse passes through the second child ul in the li, it is displayed , and when the mouse leaves, the ul is hidden.

This case makes reasonable use of the node relationships between different elements to achieve the drop-down effect conveniently and quickly.

2.3 Sibling nodes 

1. node.nextSibling

2. node.previousSibling

nextSibling returns the next sibling node of the current element, or null if not found. Likewise, all nodes are includedpreviousSibling returns the previous sibling node of the current element, or null if not found. Likewise, all nodes are included . Since the obtained nodes include all nodes, it is not recommended .

3. node.nextElementSibling

4. node.previousElementSibling

nextElementSibling returns the next sibling element node of the current element , or null if not found. previousElementSibling returns the previous sibling element node of the current element , or null if not found. However, these two methods have compatibility issues and are only supported by IE9 and above. 

How to resolve compatibility issues?

——Encapsulate a compatibility function yourself, as follows:

function getNextElementSibling(element) {
    var el = element;
    while (el = el.nextSibling) {
        if (el.nodeType === 1) {
            return el;
        }
    }
    return null;
}

3. Create nodes

document.createElement('tagName'); 

Such as: document.createElement('li') // Dynamically created a li node

The document.createElement() method creates the HTML element specified by tagName. Because these elements do not originally exist and are dynamically generated
according to our needs , we also call them dynamically created element nodes .  

4. Add nodes

1. node.appendChild(child)

The node.appendChild() method adds a node to the end of the list of children of the specified parent node . Similar to the after pseudo-element in CSS 
.

 2. node.insertBefore(child, specified element) 

The node.insertBefore() method adds a node before the specified child node of the parent node . Similar to the before pseudo-element in CSS 
.

5. Delete node

node.removeChild(child) 

The node.removeChild() method deletes a child node from the DOM and returns the deleted node . node is the parent node of the node to be deleted (the biological/nearest parent node)

 

6. Case: Simple version of posting message case

Requirements: Enter the information, click the send button, and the message will be displayed at the top of the message area on the page. And each piece of information generated comes with a delete button to delete this piece of information.

<!-- css样式 -->
<style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    .box {
        width: 400px;
        margin: 50px;
    }
    .box_send textarea {
        width: 300px;
        height: 160px;
        outline: none;
        resize: none;
    }
    .box_send button {
        padding: 5px 15px;
        vertical-align: bottom;
    }
    .box_message {
        margin-top: 15px;
    }
    .box_message li {
        width: 300px;
        line-height: 34px;
        font-size: 14px;
        text-indent: 5px;
        color: #666;
        list-style: none;
        border-bottom: 1px dashed #ccc;
    }
    .box_message li a {
        float: right;
    }
</style>
<body>
    <div class="box">
        <div class="box_send">
            <textarea id="send_data"></textarea>
            <button id="btnSend">发布</button>
        </div>
        <div class="box_message">
            <ul></ul>
        </div>
    </div>
    <script>
        // 1. 获取元素
        let textarea = document.getElementById("send_data");
        let btn = document.getElementById("btnSend");
        let ul = document.querySelector(".box_message ul");
        // 2. 给发布按钮绑定点击事件
        btn.onclick = function() {
            // 使用value获取文本域里的值,并且做非空判断
            // trim() 方法用于去除文本两端的空格,那么只输入空格也是无效内容
            if (textarea.value.trim().length <= 0) {
                return alert('请输入内容!');
            }
            // 在确定输入内容有效后,开始创建节点li
            let li = document.createElement('li');
            // 把li 节点添加至ul 中,由于最新发布的显示在最上方,所以使用insertBefore()
            ul.insertBefore(li, ul.children[0]);
      // 给li添加内容(即把文本域里的内容赋值给li,同时给li里添加一个删除链接,用来删除本条内容)
            li.innerHTML = textarea.value + '<a href="javascript:;">删除</a>';
            // 先获取a 再给 a 绑定点击事件
            let a = document.querySelector('a');
            a.onclick = function() {
                // 在删除前先提醒用户
                let flag = confirm("您确定删除吗?");
                // 如果确定,则执行删除操作
                if (flag) {
                    // 删除本条数据,即删除它的父亲
                    ul.removeChild(this.parentNode);
                }
            };
            // 添加成功后,将文本域内容清空,方便下次输入内容发布
            textarea.value = '';
        };
    </script>
</body>

case analysis:

① Core idea: After clicking the button, a li is dynamically created and added to the ul.
② When creating li, assign the value in the text field to li through li.innerHTML.
③ If you want the new message to be displayed later, use appendChild. If you want the new message to be displayed earlier, use insertBefore.

④ When we assign the value in the text field to li, add one more deleted link
⑤ We need to get the link. When we click the current link, delete the li where the current link is located
⑥ To prevent the link from jumping, we need to add javascript:void(0); or javascript:;

7. Copy node (clone node)

node.cloneNode()

The node.cloneNode() method returns a copy of the node on which the method was called. Also known as clone node/copy node  

Note:
1. If the bracket parameter is empty or false , it is a shallow copy , that is, only the copied node itself is cloned, and the child nodes inside are not cloned .
2. If the bracket parameter is true , it is a deep copy , which will copy the node itself and all its child nodes

Guess you like

Origin blog.csdn.net/JJ_Smilewang/article/details/125321755