ホームページ > 記事 > ウェブフロントエンド > ノードメソッドを挿入する JavaScript 実装の概要
JavaScript にノードを挿入するにはどうすればよいですか?この記事では、JavaScript にノードを挿入するためのいくつかの方法をまとめます。困っている友人は参考にしていただければ幸いです。
JS ネイティブ API には、innerHTML、outerHTML、appendChild、insertBefore、insertAdjacentHTML、および applyElement という 6 つのノード挿入方法があります。
ここでは、それぞれの使用法を要約し、before、prepend、append、after、applyElement などの一連の関数をカプセル化します。
1. 6 つの使用方法
innerHTML: タグ内の HTML コンテンツを取得します。
outerHTML: ターゲットタグと内部 HTML を含むコンテンツを取得します。
appendChild: ターゲット ラベルの末尾に子ノードを追加し、パラメーター ノードを返します。
insertBefore: 最初のパラメーターを子ノードとしてターゲット ノードの 2 番目のパラメーターの位置に追加し、最初のパラメーターを返します。
insertAdjacentHTML: ターゲット ノードの指定された位置にノードを追加します。2 番目のパラメータは追加するノードで、最初のパラメータには beforebegin (previousSibling として追加)、afterbegin ( firstChild として追加)、beforeend (lastChild として追加)、afterend (nextSibling として追加)。また、insertAdjacentElement と insertAdjacentText という 2 つの兄弟関数もあります。前者は要素を追加して要素を返し、後者はテキストを追加します。
applyElement: IE の関数。パラメーター ノードをターゲット ノードの外側または内側の周囲に設定します。最初のパラメーターはパラメーター ノードで、2 番目のパラメーターは内部 (内側の周囲) を含むメソッドを指定します。パラメータ ノードはターゲット ノードの子ノードをラップします)、外側(ターゲット ノードを囲みます。つまり、パラメータ ノードがターゲット ノードをラップします)。
上記の 6 つのメソッドのうち最初の 2 つ (属性) を除き、他の 4 つは関数です。 innerHTML と externalHTML については何も言うことはありません。挿入の目的は、HTML 文字列を直接割り当てることで実現できます。insertBefore は、ノードの挿入を非常に柔軟に実装できます。文字列挿入メソッド; applyElement 関数は、互換性があれば JQuery の Wrap シリーズ関数になる可能性があります。
2. ターゲット ノードの前にパラメータ ノードを挿入する前に、before、prepend、append、after 関数を実装します。ターゲット ノードの親ノードを取得するだけで済みます。その後、親ノードは insertBefore を呼び出します。 prepend は、ターゲット ノードの最初の子ノードの位置にパラメーター ノードを挿入し、ターゲット ノードの最初の子ノードを取得して、insertBefore を呼び出します。
append の機能は、ネイティブ API の appendChild の機能と同じです。
afterターゲット ノードの後ろにパラメーター ノードを挿入し、ターゲット ノードの nextSibling を取得してから、insertBefore を呼び出します。
具体的な実装は次のとおりです:
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); } };
上記の関数は、要素ノード、ドキュメント ノード、およびドキュメント フラグメントのみを挿入できます。これらはすべてノード タイプです。文字列形式での挿入をサポートしたい場合は、insertAdjacentHTML をカプセル化する必要があります。
ここでは、ストラテジ パターンを使用して、実装したい 4 つの関数をストラテジ オブジェクトに作成し、それらを動的に生成してコードを合理化する効果を実現します。
//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('beforeBegin', node); }, prependstr : function(node, scope) { scope.insertAdjacentHTML('afterBegin', node); }, appendstr : function(node, scope) { scope.insertAdjacentHTML('beforeEnd', node); }, afterstr : function(node, scope) { scope.insertAdjacentHTML('afterEnd', node); } }; //响应函数 var returnMethod = function(method, node, scope) { //如果是字符串 if(typeof node === 'string') { return insertStrategies[method + 'str'](node, scope); } //1(元素)、9(文档)、11(文档碎片) if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) { return insertStrategies[method](node, scope); } //此处还可添加节点集合的处理逻辑,用于处理选择其引擎获取的节点集合。 }; ['before', 'prepend', 'append', 'after'].forEach(function(method){ window[method] = function(node, scope) { returnMethod(method, node, scope); }; });
すべての関数が実装されていますwindow 属性として使用されるため、グローバル関数として直接呼び出すことができます。これらの関数はノード オブジェクトに属さないため、scope パラメーターはターゲット ノードを参照します。以下が applyElement と互換性を持った後、すべての関数を HTMLElement のプロトタイプに拡張し、要素ノードへの直接呼び出しの効果を実現するためにスコープ パラメーターを省略できるようにします。もちろん、フレームワークの場合、ネイティブ オブジェクトのプロトタイプの変更を避けるために、フレームワーク オブジェクトが通常生成され、その後、これらの関数がそのプロトタイプに拡張されます。
3. applyElement との互換性
applyElement 関数は IE のプライベート実装であるため、他のブラウザで使用したい場合は、 Array の forEach のようなものを使用する必要があります。また、オブジェクトのプロトタイプと互換性を持たせる必要があります。 実際、新しい要素にターゲット ノードまたはターゲット要素の子ノードを含める場合は、innerHTML と externalHTML を使用することもできます。しかし、必ず問題が発生します。新しい要素が DOM ツリーの一部であり、一連の子ノードもある場合、その子ノードはどのように処理されるべきでしょうか?所定の位置に留まるか、それともターゲット要素にマージされますか?ターゲット要素にマージされる場合、ターゲット要素が最初に来るのか、それとも新しい要素が最初に来るのか?
wrap シリーズ関数の効果は、新しい要素タグのコンテンツを削除することだけであり、その子要素の効果は、新しい要素の親ノードの子ノードになることです。このメソッドは、Range オブジェクトを使用して実装することもできます。もちろん、innerHTML および externalHTML を使用して実装することもできます。ここでは Range オブジェクトを使用して実装します。
/*兼容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 || 'outside').toLowerCase(); var range = this.ownerDocument.createRange(); if(where === 'inside') { range.selectNodeContents(this); range.surroundContents(node); range.detach(); }else if(where === 'outside') { range.selectNode(this); range.surroundContents(node); range.detach(); } return node; };
4. すべての関数を HTMLElement のプロトタイプに拡張します。
この考え方は applyElement を修復するのと同じで、ウィンドウを変更するだけです。 [メソッド] HTMLElement.prototype[メソッド]に置き換え、バッチ生成時に渡すスコープをこれに変更します。 //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('beforeBegin', node);
},
prependstr : function(node, scope) {
scope.insertAdjacentHTML('afterBegin', node);
},
appendstr : function(node, scope) {
scope.insertAdjacentHTML('beforeEnd', node);
},
afterstr : function(node, scope) {
scope.insertAdjacentHTML('afterEnd', node);
}
};
//响应函数
var returnMethod = function(method, node, scope) { //如果是字符串
if(typeof node === 'string') { //低版本浏览器使用机会毕竟少数,每次都要判断很划不来。这段代码舍弃
/*if(!scope.insertAdjacentHTML){
throw new Error('(Firefox8-、IE4-、Opera7-、Safari4-)浏览器不能插入字符串!');
}*/
return insertStrategies[method + 'str'](node, scope);
} //1(元素)、2(属性)、3(文本)、9(文档)、11(文档碎片)
if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
return insertStrategies[method](node, scope);
}
//此处还可添加节点集合的处理逻辑(用文档碎片)
};
['before', 'prepend', 'append', 'after'].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 || 'outside').toLowerCase();
var range = this.ownerDocument.createRange();
if(where === 'inside') {
range.selectNodeContents(this);
range.surroundContents(node);
range.detach();
}else if(where === 'outside') {
range.selectNode(this);
range.surroundContents(node);
range.detach();
} return node;
};
5. テスト
テスト コードは次のとおりです: 参考文献: 「JavaScript フレームワーク設計」、「JavaScript 高度なプログラミング設計」、「JavaScript 設計パターンと開発実践」 要約: 上記はこの文書の要約です。記事 すべての内容が皆様の学習に役立つことを願っています。関連チュートリアルの詳細については、JavaScript ビデオ チュートリアル 、jQuery ビデオ チュートリアル 、bootstrap チュートリアル をご覧ください。 以上がノードメソッドを挿入する JavaScript 実装の概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>插入节点.html</title>
<script type="text/javascript" src='./insertNode.js'></script>
</head>
<body>
<p id='p' style='background:#888;border:1px solid #888;padding:10px;'>坐标p</p>
<p id='inside' style='background:#0f0;border:1px solid #888;padding:10px;'>inside</p>
<p id='outside' style='background:#F00;border:1px solid #888;padding:10px;'>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>
結果の図: