Heim  >  Artikel  >  Web-Frontend  >  Zusammenfassung der JavaScript-Implementierung von Methoden zum Einfügen von Knoten

Zusammenfassung der JavaScript-Implementierung von Methoden zum Einfügen von Knoten

青灯夜游
青灯夜游nach vorne
2018-10-15 15:10:455555Durchsuche

Wie füge ich Knoten in JavaScript ein? Dieser Artikel fasst mehrere JavaScript-Methoden zum Einfügen von Knoten zusammen. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird Ihnen hilfreich sein.

Die native JS-API bietet sechs Möglichkeiten zum Einfügen von Knoten: innerHTML, äußereHTML, appendChild, insertBefore, insertAdjacentHTML und applyElement.

Hier fassen wir ihre jeweiligen Verwendungen zusammen und kapseln eine Reihe von Funktionen, darunter before, prepend, append, after und applyElement.

1. Sechs Verwendungsmöglichkeiten

innerHTML: Holen Sie sich den HTML-Inhalt innerhalb des Tags.

outerHTML: Holen Sie sich den Inhalt einschließlich des Ziel-Tags und des inneren HTML.

appendChild: Fügen Sie am Ende des Zieletiketts einen untergeordneten Knoten hinzu und geben Sie den Parameterknoten zurück.

insertBefore: Fügen Sie den ersten Parameter als untergeordneten Knoten zur zweiten Parameterposition des Zielknotens hinzu und geben Sie den ersten Parameter zurück.

insertAdjacentHTML: Fügen Sie einen Knoten an der angegebenen Position des Zielknotens hinzu. Der zweite Parameter ist der hinzuzufügende Knoten, und der erste Parameter gibt die Position an. Die Positionen umfassen beforebegin (hinzugefügt als previousSibling), afterbegin ( hinzugefügt als firstChild), beforeend (hinzugefügt als lastChild), afterend (hinzugefügt als nextSibling). Es gibt auch zwei Geschwisterfunktionen, nämlich insertAdjacentElement und insertAdjacentText. Erstere fügt ein Element hinzu und gibt das Element zurück, und letztere fügt Text hinzu.

applyElement: Die Funktion des IE legt den Parameterknoten auf die äußere oder innere Umgebung des Zielknotens fest. Der erste Parameter ist der Parameterknoten und der zweite Parameter gibt die Methode an, einschließlich der inneren Umgebung (d. h. Der Parameterknoten umschließt die untergeordneten Knoten des Zielknotens), außen (schließt den Zielknoten ein, dh der Parameterknoten umschließt den Zielknoten).

Außer die ersten beiden der oben genannten sechs Methoden sind Attribute, die anderen vier sind Funktionen. Zu innerHTML und OuterHTML gibt es nichts zu sagen. Sie können den Zweck des Einfügens durch direktes Zuweisen von HTML-Zeichenfolgen erreichen, indem Sie einfach eine Funktionsshell umschließen strings Einfügungsmethode; die applyElement-Funktion kann nach Kompatibilität zur Wrap-Serienfunktion von JQuery werden.

2. Implementieren Sie die Funktionen vor, voranstellen, anhängen und nachher

bevor Sie den Parameterknoten einfach vor dem Zielknoten einfügen Holen Sie sich den Zielknoten Der übergeordnete Knoten, und dann ruft der übergeordnete Knoten insertBefore auf.

prepend fügt den Parameterknoten in den ersten untergeordneten Knoten des Zielknotens ein, ruft den ersten untergeordneten Knoten des Zielknotens ab und ruft dann insertBefore auf.

Die Funktion von append ist dieselbe wie die Funktion von appendChild in der nativen API.

after fügt den Parameterknoten nach dem Zielknoten ein, ruft einfach das nextSibling des Zielknotens ab und ruft dann insertBefore auf.

Die spezifische Implementierung lautet wie folgt:

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);
    }
};

Die obige Funktion kann nur Elementknoten, Dokumentknoten und Dokumentfragmente einfügen, bei denen es sich alles um Knotentypen handelt. Wenn wir die Einfügemethode in Stringform unterstützen möchten, müssen wir insertAdjacentHTML kapseln.

Hier verwende ich das Strategiemuster, um die vier Funktionen, die ich implementieren möchte, in Strategieobjekte umzuwandeln und sie dann dynamisch zu generieren, um den Effekt einer Optimierung des Codes zu erzielen:

//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);
    };
});

Alle Funktionen sind implementiert als Fensterattribute, sodass sie direkt als globale Funktionen aufgerufen werden können. Diese Funktionen gehören nicht zu Knotenobjekten, daher bezieht sich der Bereichsparameter auf den Zielknoten. Nachdem das Folgende mit applyElement kompatibel ist, erweitern wir alle Funktionen auf den Prototyp von HTMLElement, sodass der Scope-Parameter weggelassen werden kann, um den Effekt eines direkten Aufrufs des Elementknotens zu erzielen. Natürlich wird bei Frameworks im Allgemeinen das Framework-Objekt generiert und diese Funktionen dann auf seinen Prototyp erweitert, um eine Änderung des Prototyps des nativen Objekts zu vermeiden.

3. Kompatibel mit applyElement

Die applyElement-Funktion ist eine private Implementierung von IE. Wenn Sie sie also in anderen Browsern verwenden möchten, Wir müssen Arrays forEach ähneln und es auch mit dem Objektprototyp kompatibel machen.

Wenn Sie möchten, dass das neue Element den Zielknoten oder die untergeordneten Knoten des Zielelements enthält, können Sie tatsächlich auch innerHTML und äußereHTML verwenden. Aber es gibt zwangsläufig ein Problem: Wenn das neue Element Teil des DOM-Baums ist und auch eine Reihe von untergeordneten Knoten hat, wie sollen seine untergeordneten Knoten verarbeitet werden? An Ort und Stelle bleiben oder mit dem Zielelement verschmelzen? Steht bei der Zusammenführung mit dem Zielelement das Zielelement oder das neue Element an erster Stelle?

Der Effekt der Wrap-Serien-Funktion besteht nur darin, den Inhalt im neuen Element-Tag zu entfernen, und der Effekt seiner untergeordneten Elemente besteht darin, zum untergeordneten Knoten des übergeordneten Knotens des neuen Elements zu werden. Diese Methode kann auch mit Range-Objekten implementiert werden, und natürlich kann sie auch mit innerHTML und OuterHTML implementiert werden. Ich werde das Range-Objekt verwenden, um es hier zu implementieren.

/*兼容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;
};

4. Erweitern Sie alle Funktionen auf den Prototyp von HTMLElement

Die Idee ist die gleiche wie beim Reparieren von applyElement, wir müssen nur das Fenster ändern [Methode] Ersetzen Sie es durch HTMLElement.prototype[Methode] und ändern Sie den während der Stapelgenerierung übergebenen Bereich in diesen.

//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;
};

5. Test

Der Testcode lautet wie folgt:

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

Ergebnisbild:

Bibliographie: „Javascript Framework Design“, „Javascript Advanced Programming Design“, „JavaScript Design Patterns and Development Practices“

Zusammenfassung: Das Obige ist die Zusammenfassung davon Artikel Alle Inhalte, ich hoffe, dass es für das Studium aller hilfreich sein wird. Weitere verwandte Tutorials finden Sie unter JavaScript-Video-Tutorial, jQuery-Video-Tutorial, Bootstrap-Tutorial!

Das obige ist der detaillierte Inhalt vonZusammenfassung der JavaScript-Implementierung von Methoden zum Einfügen von Knoten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen