Home > Web Front-end > JS Tutorial > body text

Summary of JavaScript implementation of inserting node methods

青灯夜游
Release: 2018-10-15 15:12:53
forward
5565 people have browsed it

How to insert nodes in JavaScript? This article summarizes several methods for inserting nodes in JavaScript. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

The JS native API has six ways of inserting nodes: innerHTML, outerHTML, appendChild, insertBefore, insertAdjacentHTML, and applyElement.

Here we summarize their respective usages and encapsulate a series of functions including before, prepend, append, after, and applyElement.

1. Six ways of usage

innerHTML: Get the HTML content inside the tag.

outerHTML: Get the content including the target tag and the inner HTML.

appendChild: Add a child node to the end of the target label and return the parameter node.

insertBefore: Add the first parameter as a child node to the second parameter position of the target node and return the first parameter.

insertAdjacentHTML: Add a node to the specified position of the target node; the second parameter is the node to be added, and the first parameter specifies the position. The positions include beforebegin (added as previousSibling), afterbegin (added as firstChild), beforeend (added as lastChild), afterend (added as nextSibling). It also has two sibling functions, namely insertAdjacentElement and insertAdjacentText. The former adds an element and returns the element, and the latter adds text.

applyElement: IE's function, sets the parameter node to the outer or inner surrounding of the target node; the first is the parameter node, and the second parameter specifies the method, including inside (inner surround, that is, the parameter node Wrap the child nodes of the target node), outside (enclose the target node, that is, the parameter node wraps the target node).

Except for the first two of the above six methods, which are attributes, the other four are functions. There is nothing to say about innerHTML and outerHTML. The purpose of insertion can be achieved by directly assigning HTML strings; appendChild can be encapsulated into the append function by simply wrapping a function shell; insertBefore makes the insertion method of nodes very flexible; insertAdjacentHTML can implement strings Insertion method; the applyElement function can become JQuery's Wrap series function after compatibility.

2. Implement the before, prepend, append, and after functions

before insert the parameter node in front of the target node, and only need to obtain the target node The parent node, and then the parent node calls insertBefore.

prepend inserts the parameter node into the position of the first child node of the target node, obtains the first child node of the target node, and then calls insertBefore.

The function of append is the same as the function of appendChild in the native API.

afterInsert the parameter node behind the target node, just get the nextSibling of the target node, and then call insertBefore.

The specific implementation is as follows:

var append = function(node, scope) {    
     if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
        scope.appendChild(node);
    }
};
var prepend = function(node, scope) {    
     if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
        scope.insertBefore(node, scope.firstChild);
    }
};
var before = function(node, scope) {    
     if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
        scope.parentNode.insertBefore(node, scope);
    }
};
var after = function(node, scope) {    
     if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
        scope.parentNode.insertBefore(node, scope.nextSibling);
    }
};
Copy after login

The above function can only insert element nodes, document nodes and document fragments, which are all node types. If we want to support insertion in string form, we need to encapsulate insertAdjacentHTML.

Here I use the strategy pattern to make the four functions I want to implement into strategy objects, and then dynamically generate them to achieve the effect of streamlining the code:

//E5才有的迭代, 所以迭代要预先兼容
Array.prototype.forEach = [].forEach || function(callback) {    
      for(var i = 0, len = this.length; i < len; i++) {
        callback.call(this[i], this[i], i, this);
    }
};  
/**插入策略集合**/ 
var insertStrategies = {
    before : function(node, scope) {
        scope.parentNode.insertBefore(node, scope);
    },
    prepend : function(node, scope) {
        scope.insertBefore(node, scope.firstChild);
    },
    append : function(node, scope) {
        scope.appendChild(node);
    },
    after : function(node, scope) {
        scope.parentNode.insertBefore(node, scope.nextSibling);
    },    
    /*支持字符串格式的插入, 注意:要兼容不可直接做p子类的元素*/
    /*insertAdjace还有Element和Text,前者只能插元素,后者只能插文本*/
    beforestr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;beforeBegin&#39;, node);
    },
    prependstr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;afterBegin&#39;, node);
    },
    appendstr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;beforeEnd&#39;, node);
    },
    afterstr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;afterEnd&#39;, node);
    }
};
//响应函数
var returnMethod = function(method, node, scope) {    //如果是字符串
    if(typeof node === &#39;string&#39;) {        
        return insertStrategies[method + &#39;str&#39;](node, scope);
    }    
    //1(元素)、9(文档)、11(文档碎片)
    if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {        
          return insertStrategies[method](node, scope);
    }    
    //此处还可添加节点集合的处理逻辑,用于处理选择其引擎获取的节点集合。
};

[&#39;before&#39;, &#39;prepend&#39;, &#39;append&#39;, &#39;after&#39;].forEach(function(method){
    window[method] = function(node, scope) {
        returnMethod(method, node, scope);
    };
});
Copy after login

All functions are implemented as window Attributes, so they can be called directly as global functions. These functions do not belong to node objects, so the scope parameter refers to the target node. After the following is compatible with applyElement, we will extend all functions to the prototype of HTMLElement, so that the scope parameter can be omitted to achieve the effect of direct call to the element node. Of course, for frameworks, the framework object is generally generated, and then these functions are extended to its prototype, so as to avoid modifying the prototype of the native object.

3. Compatible with applyElement

The applyElement function is a private implementation of IE, so if we want to use it in other browsers, we have to use something like Array’s forEach Also make it compatible with the object prototype.

In fact, if you want the new element to contain the target node or contain the child nodes of the target element, you can also use innerHTML and outerHTML. But there is bound to be a problem: when the new element is part of the DOM tree, and it also has a series of child nodes, how should its child nodes be processed? Stay in place or merge into the target element? If merged into the target element, does the target element or the new element come first?

The effect of the wrap series function is only to remove the content in the new element tag, and the effect of its child elements is to become the child node of the new element's parent node. This method can also be implemented using Range objects, and of course it can also be implemented using innerHTML and outerHTML. I'll use the Range object to implement it here.

/*兼容IE的applyElement*/
HTMLElement.prototype.removeNode = HTMLElement.prototype.removeNode || function(deep) {    
       if(this.parentNode) {        
            var range = this.ownerDocument.createRange();
        range.selectNodeContents(this);        
        if(!deep) {            
               var fragment = range.extractContents();
            range.setStartBefore(this);
            range.insertNode(fragment);
            range.detach();
        }        
        return this.parentNode.removeChild(this);
    }
}; 

HTMLElement.prototype.applyElement = HTMLElement.prototype.applyElement || function(node, where) {
    node = node.removeNode();
    where = (where || &#39;outside&#39;).toLowerCase();    
    var range = this.ownerDocument.createRange();    
    if(where === &#39;inside&#39;) {
        range.selectNodeContents(this);
        range.surroundContents(node);
        range.detach();
    }else if(where === &#39;outside&#39;) {
        range.selectNode(this);
        range.surroundContents(node);
        range.detach();
    }    
    return node;
};
Copy after login

4. Extend all functions to the prototype of HTMLElement

The idea is the same as repairing applyElement, we only need to change window[method] Replace it with HTMLElement.prototype[method], and change the scope passed during batch generation to this.

//E5才有的迭代, 所以迭代要预先兼容
Array.prototype.forEach = [].forEach || function(callback) {    
        for(var i = 0, len = this.length; i < len; i++) {
        callback.call(this[i], this[i], i, this);
    }
};  

/**插入策略集合**/
var insertStrategies = {
    before : function(node, scope) {
        scope.parentNode.insertBefore(node, scope);
    },
    prepend : function(node, scope) {
        scope.insertBefore(node, scope.firstChild);
    },
    append : function(node, scope) {
        scope.appendChild(node);
    },
    after : function(node, scope) {
        scope.parentNode.insertBefore(node, scope.nextSibling);
    },    
    /*支持字符串格式的插入, 注意:要兼容不可直接做p子类的元素*/
    /*insertAdjace还有Element和Text,前者只能插元素,后者只能插文本*/
    /**/
    beforestr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;beforeBegin&#39;, node);
    },
    prependstr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;afterBegin&#39;, node);
    },
    appendstr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;beforeEnd&#39;, node);
    },
    afterstr : function(node, scope) {
        scope.insertAdjacentHTML(&#39;afterEnd&#39;, node);
    }
};
//响应函数
var returnMethod = function(method, node, scope) {    //如果是字符串
    if(typeof node === &#39;string&#39;) {   //低版本浏览器使用机会毕竟少数,每次都要判断很划不来。这段代码舍弃
        /*if(!scope.insertAdjacentHTML){
            throw new Error(&#39;(Firefox8-、IE4-、Opera7-、Safari4-)浏览器不能插入字符串!&#39;);
        }*/
        return insertStrategies[method + &#39;str&#39;](node, scope);
    }    //1(元素)、2(属性)、3(文本)、9(文档)、11(文档碎片)
    if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {        
            return insertStrategies[method](node, scope);
    }    
    //此处还可添加节点集合的处理逻辑(用文档碎片)
};

[&#39;before&#39;, &#39;prepend&#39;, &#39;append&#39;, &#39;after&#39;].forEach(function(method){
    HTMLElement.prototype[method] = function(node) {
        returnMethod(method, node, this);
    };
});/*兼容IE的applyElement*/
HTMLElement.prototype.removeNode = HTMLElement.prototype.removeNode || function(deep) {    
        if(this.parentNode) {        
                var range = this.ownerDocument.createRange();
        range.selectNodeContents(this);        
        if(!deep) {            
                var fragment = range.extractContents();
            range.setStartBefore(this);
            range.insertNode(fragment);
            range.detach();
        }        
        return this.parentNode.removeChild(this);
    }
}; 

HTMLElement.prototype.applyElement = HTMLElement.prototype.applyElement || function(node, where) {
    node = node.removeNode();
    where = (where || &#39;outside&#39;).toLowerCase();    
    var range = this.ownerDocument.createRange();    
    if(where === &#39;inside&#39;) {
        range.selectNodeContents(this);
        range.surroundContents(node);
        range.detach();
    }else if(where === &#39;outside&#39;) {
        range.selectNode(this);
        range.surroundContents(node);
        range.detach();
    }    return node;
};
Copy after login

5. Test

The test code is as follows:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>插入节点.html</title>
    <script type="text/javascript" src=&#39;./insertNode.js&#39;></script>
  </head>
  <body>
    <p id=&#39;p&#39; style=&#39;background:#888;border:1px solid #888;padding:10px;&#39;>坐标p</p>
    <p id=&#39;inside&#39; style=&#39;background:#0f0;border:1px solid #888;padding:10px;&#39;>inside</p>
    <p id=&#39;outside&#39; style=&#39;background:#F00;border:1px solid #888;padding:10px;&#39;>outside</p>
    
    <script type="text/javascript">        
            var p = document.getElementById('p');        
        var beforep = document.createElement('p');
        beforep.innerHTML = 'beforep';
        beforep.style.background = '#eee';        
        var prepEndp = document.createElement('p');
        prepEndp.innerHTML = 'prepEndp';
        prepEndp.style.background = '#ff0';        
        var appendp = document.createElement('p');
        appendp.innerHTML = 'appendp';
        appendp.style.background = '#0ff';        
        var afterp = document.createElement('p');
        afterp.innerHTML = 'afterp';
        afterp.style.background = '#f0f';
        
        p.before(beforep);
        p.prepend(prepEndp);
        p.append(appendp);
        p.after(afterp);        
        //测试文本插入
        p.append('[我是乐小天,我来测试直接插入文本]');        
        //测试外包含和内包含
        var outside = document.getElementById('outside');        
        var inside = document.getElementById('inside');
        outside.applyElement(inside, 'inside');    
     </script>
  </body>
</html>
Copy after login

Result picture:

Bibliography: "Javascript Framework Design", "Javascript Advanced Programming Design", "JavaScript Design Patterns and Development Practices"

Summary: The above is the summary of this article All content, I hope it will be helpful to everyone's study. For more related tutorials, please visit JavaScript Video Tutorial, jQuery Video Tutorial, bootstrap Tutorial!

The above is the detailed content of Summary of JavaScript implementation of inserting node methods. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:cnblogs.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template