組み込みのDOMメソッドまたはプロトタイプを使用して、HTML文字列から新しいDOM要素を作成する


621

要素を表すHTML文字列があります:'<li>text</li>'。それをDOMの要素(ul私の場合はa )に追加したいと思います。プロトタイプまたはDOMメソッドでこれを行うにはどうすればよいですか?

(私はこれをjQueryで簡単に実行できることを知っていますが、残念ながら私たちはjQueryを使用していません。)


申し訳ありませんが、正確に何を達成しようとしていますか?HTML文字列-> dom要素?
クレセントフレッシュ

36
これらのソリューションが非常に間接的であることは残念です。私は、標準化委員会のような似たような指定ほしい:var nodes = document.fromString("<b>Hello</b> <br>");
シュリダールSarnobat


1
渡される必要のある属性があり、それらを解析したくなかったため、上記の問題がありました: "<table id = '5ccf9305-4b10-aec6-3c55-a6d218bfb107' class = 'data-table row-border display 'cellspacing =' 0 'width =' 100% '> </ table> "なので、単純に次のように使用しました:$(" <table id =' 5ccf9305-4b10-aec6-3c55-a6d218bfb107 'class =' data -table row-border display 'cellspacing =' 0 'width =' 100% '> </ table> ")
stevenlacerda

回答:


818

注:現在のほとんどのブラウザはHTML <template>要素をサポートしています。HTML 要素は、文字列から要素を作成するための信頼性の高い方法を提供します。詳細については、以下のMark Ameryの回答を参照してください

古いブラウザ、およびnode / jsdom:(<template>執筆時点ではまだ要素をサポートしていません)には、次のメソッドを使用します。これは、ライブラリがHTML文字列からDOM要素を取得するために使用するものと同じです(IEがの実装でバグを回避するための追加作業が必要ですinnerHTML)。

function createElementFromHTML(htmlString) {
  var div = document.createElement('div');
  div.innerHTML = htmlString.trim();

  // Change this to div.childNodes to support multiple top-level nodes
  return div.firstChild; 
}

HTMLテンプレートとは異なり、このことに注意してくださいません合法的に子供たちにはできませんいくつかの要素のために働く<div>ような、<td>S。

すでにライブラリを使用している場合は、ライブラリで承認されているHTML文字列から要素を作成する方法を使用することをお勧めします。


1
この安全でないinnerHTML割り当てを使用せずにjQueryを使用してinnerHTMLを作成済みのdivに設定する方法(div.innerHTML = "some value")
Shivanshu Goyal

12
関数名createElementFromHTML は、eg でないaをdiv.firstChild返すので誤解を招く可能性があります。代わりに関数からの戻りを作成します。NodeHTMLElementnode.setAttributeElementdiv.firstElementChild
Semmel

ありがとう、<div>私が追加したHTML のラッピングは.innerHTML私を困らせました。を使用することを考えたことはありません.firstChild
イヴァン

作成したSVG内でSVGを解析しようdivとしていますが[object SVGSVGElement]、コンソールログから正しいDOM要素が出力されます。何が悪いのですか?
ed1nh0

1
私の代わりのfirstChild(参照のfirstElementChildを使用することになりw3schools.com/jsref/prop_element_firstelementchild.asp前面またはテンプレートの末尾にスペースがある場合、のfirstChildは空textNode戻ってくるので、)
クリスPanayotoff

342

HTML 5は、<template>この目的に使用できる要素を導入しました(現在、WhatWG仕様MDNドキュメントで説明されています))。

<template>要素は、スクリプトで利用できるHTMLの断片を宣言するために使用されます。要素は、型のプロパティHTMLTemplateElementを持つとしてDOMで表され、テンプレートのコンテンツへのアクセスを提供します。あなたが設定することにより、DOM要素にHTML文字列を変換することができることをこれは意味の、その後に到達し、要素をさん.contentDocumentFragmentinnerHTML<template>template.contentプロパティ。

例:

/**
 * @param {String} HTML representing a single element
 * @return {Element}
 */
function htmlToElement(html) {
    var template = document.createElement('template');
    html = html.trim(); // Never return a text node of whitespace as the result
    template.innerHTML = html;
    return template.content.firstChild;
}

var td = htmlToElement('<td>foo</td>'),
    div = htmlToElement('<div><span>nested</span> <span>stuff</span></div>');

/**
 * @param {String} HTML representing any number of sibling elements
 * @return {NodeList} 
 */
function htmlToElements(html) {
    var template = document.createElement('template');
    template.innerHTML = html;
    return template.content.childNodes;
}

var rows = htmlToElements('<tr><td>foo</td></tr><tr><td>bar</td></tr>');

ような別のコンテナー要素div使用する同様のアプローチはうまく機能しないことに注意してください。HTMLには、他のどの要素タイプ内に存在できる要素タイプに制限があります。たとえば、をtdの直接の子として配置することはできませんdiv。これは、あなたが設定しようとすると消えるために、これらの要素の原因となるinnerHTMLのがdiv、それらを含むように。<template>にはコンテンツに対するそのような制限がないため、この欠点はテンプレートを使用する場合には当てはまりません。

ただし、template一部の古いブラウザではサポートされていません。2018年1月、のようすることができます私の使用...推定したユーザーの90%がグローバルにサポートしているブラウザを使用しているtemplate。特に、それらをサポートするInternet Explorerのバージョンはありません。MicrosoftはtemplateEdgeのリリースまでサポートを実装しませんでした。

運が良ければ、最新のブラウザーのユーザーのみを対象とするコードを作成できるのであれば、今すぐ使用してください。そうしないと、ユーザーが追いつくのにしばらく待たなければならない場合があります。


9
素敵な、モダンなアプローチ。Operaでテスト済み、IEを忘れましょう
Adi Prasetyo

2
これは効果的なアプローチであり、非常にクリーンです。ただし、(少なくともChrome 50では)これはスクリプトタグの処理に影響します。つまり、このメソッドを使用してスクリプトタグを作成し、それをドキュメント(本文または頭)に追加しても、タグが評価されず、スクリプトが実行されません。(評価がアタッチで発生する場合、これは仕様による可能性があります。確信が持てません。)
shanef22

1
素敵!次のようなことを行うことで要素をクエリすることもできます:template.content.querySelector( "img");
Roger Gajraj

1
@クレセントフレッシュ:結構です、あなたはそれが今は無関係であると言ったので、あなたの答えが消えてほしかった印象でした、私の謝罪。良い妥協案は、今メタで議論されているように、読者にこれを指し示す回答にステートメントを追加することです-編集戦争がそこから回復しないことを願いましょう。
BoltClock

2
これには1つの問題があります。開始または終了にスペース(!)があるタグがそこにある場合、それらは削除されます!誤解しないでください。これはhtml.trim、innerHTML設定の内部解析によって削除されたスペースに関するものではありません。私の場合、textNodeの一部である重要なスペースを削除します。:-(
e-motiv 2018

110

insertAdjacentHTML()を使用します。IE11でも、現在のすべてのブラウザーで動作します。

var mylist = document.getElementById('mylist');
mylist.insertAdjacentHTML('beforeend', '<li>third</li>');
<ul id="mylist">
 <li>first</li>
 <li>second</li>
</ul>


9
まず、insertAdjacentHTMLIE 4.0以降のすべてのブラウザーで動作します。
JonasÄppelgran18年

6
第二に、それは素晴らしいです!と比較した大きなプラスinnerHTML += ...は、以前の要素への参照がこのメソッドを使用してもまだ影響を受けないことです。
JonasÄppelgran18年

7
最初の引数のための第三に、可能な値は次のとおりですbeforebeginafterbeginbeforeendafterend。MDNの記事を参照してください。
JonasÄppelgran18年

私へのベストアンサー
ジョーダン

4
残念ながら、挿入されたHTMLを要素として返しません
Mojimi

30

新しいDOM実装にはrange.createContextualFragmentがあり、フレームワークに依存しない方法で必要な処理を実行します。

広くサポートされています。ただし、変更されるので、同じMDNリンクで互換性を確認してください。2017年5月現在、これは次のとおりです。

Feature         Chrome   Edge   Firefox(Gecko)  Internet Explorer   Opera   Safari
Basic support   (Yes)    (Yes)  (Yes)           11                  15.0    9.1.2

3
これにはinnerHTMLdivの設定と同様の欠点があることに注意してください。tds などの特定の要素は無視され、結果のフラグメントには表示されません。
Mark Amery 2016

「デスクトップSafariが一度にRange.createContextualFragment()をサポートしたという報告がありますが、少なくともSafari 9.0および9.1ではサポートされていません。」(回答のMDNリンク)
akauppi

27

微調整の必要はありません、あなたはネイティブAPIを手に入れました:

const toNodes = html =>
    new DOMParser().parseFromString(html, 'text/html').body.childNodes[0]

9
これには、受け入れられた回答と同じ大きな欠点があり、HTMLを次のように壊してしまいます<td>text</td>。これは、DOMParserHTMLドキュメント全体を解析しようとしているためであり、すべての要素がドキュメントのルート要素として有効であるとは限りません。
Mark Amery 2017

4
-1これは、上記のコメントで言及した欠点を明示的に指摘した以前の回答の複製です。
Mark Amery 2017

20

<td>test</td>div.innerHTML、DOMParser.parseFromStringおよびrange.createContextualFragment(正しいコンテキストなし)のような特定のhtmlフラグメントの場合、ここで他の回答で言及されているソリューションでは、<td>要素は作成されません。

jQuery.parseHTML()はそれらを適切に処理します(私はjQuery 2のparseHTML関数を独立した関数に抽出しました非jqueryコードベースで使用できる)。

Edge 13+のみをサポートしている場合は、HTML5テンプレートタグを使用する方が簡単です。

function parseHTML(html) {
    var t = document.createElement('template');
    t.innerHTML = html;
    return t.content.cloneNode(true);
}

var documentFragment = parseHTML('<td>Test</td>');

16

これを行う簡単な方法を次に示します。

String.prototype.toDOM=function(){
  var d=document
     ,i
     ,a=d.createElement("div")
     ,b=d.createDocumentFragment();
  a.innerHTML=this;
  while(i=a.firstChild)b.appendChild(i);
  return b;
};

var foo="<img src='//placekitten.com/100/100'>foo<i>bar</i>".toDOM();
document.body.appendChild(foo);

4
@MarkAmeryここでの違いは、彼がフラグメントを使用して複数のルート要素をDOMに追加できることです。これは追加の利点です。ウィリアムだけがそれが彼の答えだと述べたなら
公園。

10

以下を使用して、文字列から有効なDOMノードを作成できます。

document.createRange().createContextualFragment()

次の例では、文字列からマークアップを取得するボタン要素をページに追加します。

let html = '<button type="button">Click Me!</button>';
let fragmentFromString = function (strHTML) {
  return document.createRange().createContextualFragment(strHTML);
}
let fragment = fragmentFromString(html);
document.body.appendChild(fragment);


5
これはDocumentFragmentオブジェクトを作成しますが、それでも -驚いたことに-受け入れられた回答と同じ欠陥に悩まさdocument.createRange().createContextualFragment('<td>bla</td>')れています。そうすると、<td>要素のない「bla」というテキストのみを含むフラグメントが得られます。あるいは、少なくとも、私がChrome 63でそれを観察しています。私はそれが正しい動作であるかどうかを理解するために仕様を掘り下げていません。
Mark Amery 2017

9

プロトタイプでは、次のことも実行できます。

HTML:

<ul id="mylist"></ul>

JS:

$('mylist').insert('<li>text</li>');

これはjQueryですか?またはJS?
Jeya Suriya Muthumari

1
これは、前述のように組み込みDOMメソッドではなくjQueryを使用しています。
Juan Hurtado

1
@JuanHurtadoこれは、約11年前にOPが要求されたPrototypeJsを使用しています;)
Pablo Borowicz

8

私はこの方法を使用しています(IE9 +で機能します)が、解析されない<td>か、または他のいくつかの無効な直接の子の本体がありません。

function stringToEl(string) {
    var parser = new DOMParser(),
        content = 'text/html',
        DOM = parser.parseFromString(string, content);

    // return element
    return DOM.body.childNodes[0];
}

stringToEl('<li>text</li>'); //OUTPUT: <li>text</li>

5

さらに便利強化するために()が.toDOM私たちは別の場所で見つけることができるというスニペットを、私たちは今、することができ、安全に使うバッククォートテンプレートリテラル)。

したがって、foo html宣言で一重引用符と二重引用符を使用できます。

これは、用語に精通している人にとってはヒアドキュメントのように動作します。

これは、変数でさらに拡張して、複雑なテンプレートを作成できます。

テンプレートリテラルは、二重引用符または単一引用符ではなく、バックティック()(グレーブアクセント)文字で囲まれています。テンプレートリテラルにはプレースホルダーを含めることができます。これらは、ドル記号と中括弧($ {expression})で示されます。プレースホルダー内の式とそれらの間のテキストは関数に渡されます。デフォルトの関数は、パーツを1つの文字列に連結するだけです。テンプレートリテラル(ここでタグ)の前に式がある場合、これは「タグ付きテンプレート」と呼ばれます。その場合、タグ式(通常は関数)は処理されたテンプレートリテラルを使用して呼び出され、出力する前に操作できます。テンプレートリテラルでバックティックをエスケープするには、バックティックの前にバックスラッシュ\を置きます。

String.prototype.toDOM=function(){
  var d=document,i
     ,a=d.createElement("div")
     ,b=d.createDocumentFragment()
  a.innerHTML = this
  while(i=a.firstChild)b.appendChild(i)
  return b
}

// Using template litterals
var a = 10, b = 5
var foo=`
<img 
  onclick="alert('The future start today!')"   
  src='//placekitten.com/100/100'>
foo${a + b}
  <i>bar</i>
    <hr>`.toDOM();
document.body.appendChild(foo);
img {cursor: crosshair}

では、なぜ直接使用しないの.innerHTML +=ですか?そうすることで、DOM全体がブラウザによって再計算され、速度が大幅に低下します。

https://caniuse.com/template-literals



3

HTML5およびES6

<template>

デモ

"use strict";

/**
 *
 * @author xgqfrms
 * @license MIT
 * @copyright xgqfrms
 * @description HTML5 Template
 * @augments
 * @example
 *
 */

/*

<template>
    <h2>Flower</h2>
    <img src="https://www.w3schools.com/tags/img_white_flower.jpg">
</template>


<template>
    <div class="myClass">I like: </div>
</template>

*/

const showContent = () => {
    // let temp = document.getElementsByTagName("template")[0],
    let temp = document.querySelector(`[data-tempalte="tempalte-img"]`),
        clone = temp.content.cloneNode(true);
    document.body.appendChild(clone);
};

const templateGenerator = (datas = [], debug = false) => {
    let result = ``;
    // let temp = document.getElementsByTagName("template")[1],
    let temp = document.querySelector(`[data-tempalte="tempalte-links"]`),
        item = temp.content.querySelector("div");
    for (let i = 0; i < datas.length; i++) {
        let a = document.importNode(item, true);
        a.textContent += datas[i];
        document.body.appendChild(a);
    }
    return result;
};

const arr = ["Audi", "BMW", "Ford", "Honda", "Jaguar", "Nissan"];

if (document.createElement("template").content) {
    console.log("YES! The browser supports the template element");
    templateGenerator(arr);
    setTimeout(() => {
        showContent();
    }, 0);
} else {
    console.error("No! The browser does not support the template element");
}
@charset "UTf-8";

/* test.css */

:root {
    --cololr: #000;
    --default-cololr: #fff;
    --new-cololr: #0f0;
}

[data-class="links"] {
    color: white;
    background-color: DodgerBlue;
    padding: 20px;
    text-align: center;
    margin: 10px;
}
<!DOCTYPE html>
<html lang="zh-Hans">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Template Test</title>
    <!--[if lt IE 9]>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.js"></script>
    <![endif]-->
</head>

<body>
    <section>
        <h1>Template Test</h1>
    </section>
    <template data-tempalte="tempalte-img">
        <h3>Flower Image</h3>
        <img src="https://www.w3schools.com/tags/img_white_flower.jpg">
    </template>
    <template data-tempalte="tempalte-links">
        <h3>links</h3>
        <div data-class="links">I like: </div>
    </template>
    <!-- js -->
</body>

</html>


2

遅いですが、メモとして。

簡単な要素をコンテナーとしてターゲット要素に追加し、使用後に削除することができます。

// chrome 23.0、firefox 18.0、つまり7-8-9とOpera 12.11でテスト済み。

<div id="div"></div>

<script>
window.onload = function() {
    var foo, targetElement = document.getElementById('div')
    foo = document.createElement('foo')
    foo.innerHTML = '<a href="#" target="_self">Text of A 1.</a> '+
                    '<a href="#" onclick="return !!alert(this.innerHTML)">Text of <b>A 2</b>.</a> '+
                    '<hr size="1" />'
    // Append 'foo' element to target element
    targetElement.appendChild(foo)

    // Add event
    foo.firstChild.onclick = function() { return !!alert(this.target) }

    while (foo.firstChild) {
        // Also removes child nodes from 'foo'
        targetElement.insertBefore(foo.firstChild, foo)
    }
    // Remove 'foo' element from target element
    targetElement.removeChild(foo)
}
</script>

2

文字列からDOMをレンダリングする最速のソリューション:

let render = (relEl, tpl, parse = true) => {
  if (!relEl) return;
  const range = document.createRange();
  range.selectNode(relEl);
  const child = range.createContextualFragment(tpl);
  return parse ? relEl.appendChild(child) : {relEl, el};
};

そしてここ uはDOM操作のパフォーマンスをチェックすることができ、ネイティブJS対リアクト

今、あなたは単に使うことができます:

let element = render(document.body, `
<div style="font-size:120%;line-height:140%">
  <p class="bold">New DOM</p>
</div>
`);

そしてもちろん、近い将来、メモリからの参照を使用します。var "element"は、ドキュメント内に新しく作成されたDOMです。

そして「innerHTML =」は非常に遅いことを覚えておいてください:/


1

これが私のコードです、そしてそれは機能します:

function parseTableHtml(s) { // s is string
    var div = document.createElement('table');
    div.innerHTML = s;

    var tr = div.getElementsByTagName('tr');
    // ...
}

1
作成される要素自体がテーブルの場合、失敗します。
Mark Amery 2016

0

全体として、私が思いついたのは、複雑ではあるが単純なアプローチでこれを共有することだと思いました...多分誰かが何か便利なものを見つけるでしょう。

/*Creates a new element - By Jamin Szczesny*/
function _new(args){
    ele = document.createElement(args.node);
    delete args.node;
    for(x in args){ 
        if(typeof ele[x]==='string'){
            ele[x] = args[x];
        }else{
            ele.setAttribute(x, args[x]);
        }
    }
    return ele;
}

/*You would 'simply' use it like this*/

$('body')[0].appendChild(_new({
    node:'div',
    id:'my-div',
    style:'position:absolute; left:100px; top:100px;'+
          'width:100px; height:100px; border:2px solid red;'+
          'cursor:pointer; background-color:HoneyDew',
    innerHTML:'My newly created div element!',
    value:'for example only',
    onclick:"alert('yay')"
}));

0

なぜネイティブjsを使わないのですか?

    var s="<span class='text-muted' style='font-size:.75em; position:absolute; bottom:3px; left:30px'>From <strong>Dan's Tools</strong></span>"
    var e=document.createElement('div')
    var r=document.createRange();
    r.selectNodeContents(e)
    var f=range.createContextualFragment(s);
    e.appendChild(f);
    e = e.firstElementChild;

-1
function domify (str) {
  var el = document.createElement('div');
  el.innerHTML = str;

  var frag = document.createDocumentFragment();
  return frag.appendChild(el.removeChild(el.firstChild));
}

var str = "<div class='foo'>foo</div>";
domify(str);

-2

次の関数を使用して、テキスト「HTML」を要素に変換できます

function htmlToElement(html)
{
  var element = document.createElement('div');
  element.innerHTML = html;
  return(element);
}
var html="<li>text and html</li>";
var e=htmlToElement(html);


-1; これは、承認された回答で提案されているものと同じ手法であり、同じ欠点がありtdます。特に、s では機能しません。
Mark Amery 2017

-3
var jtag = $j.li({ child:'text' }); // Represents: <li>text</li>
var htmlContent = $('mylist').html();
$('mylist').html(htmlContent + jtag.html());

jneratorを使用する


-3

ここに私のための作業コードがあります

' Text '文字列をHTML要素に変換したかった

var diva = UWA.createElement('div');
diva.innerHTML = '<a href="http://wwww.example.com">Text</a>';
var aelement = diva.firstChild;

なにwwww
Tintin81

-3

var msg = "test" jQuery.parseHTML(msg)


このコードスニペットをお寄せいただきありがとうございます。このコードスニペットは、限られた、即時の助けを提供する可能性があります。適切な説明が大幅にこれは問題に良い解決策であり、他、同様の質問を将来の読者にそれがより便利になるだろう、なぜ示すことによって、その長期的な価値を向上させるであろう。答えを編集して、仮定を含めて説明を追加してください。
Dwhitz

-7

これも機能します:

$('<li>').text('hello').appendTo('#mylist');

これは、チェーンされた関数呼び出しを使用したjqueryの方法に似ています。


26
jQueryだからjQueryみたいな感じ?
Tim Ferrell、

5
その最後の行はただ陽気です!
kumarharsh 2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.