it-swarm.com.de

Erstellen eines neuen DOM-Elements aus einer HTML-Zeichenfolge mit integrierten DOM-Methoden oder Prototype

Ich habe eine HTML-Zeichenfolge, die ein Element darstellt: '<li>text</li>'. Ich möchte es an ein Element im DOM anhängen (ein ul in meinem Fall). Wie kann ich das mit Prototype oder mit DOM-Methoden machen?

(Ich weiß, ich könnte dies leicht in jQuery tun, aber leider verwenden wir jQuery nicht.)

523
Omer Bokhari

Hinweis: Die meisten aktuellen Browser unterstützen HTML _<template>_ -Elemente, die eine zuverlässigere Möglichkeit bieten, Elemente aus Zeichenfolgen zu erstellen. Siehe Mark Amerys Antwort unten für Details .

Für ältere Browser und node/jsdom : (das zum Zeitpunkt des Schreibens noch keine _<template>_ -Elemente unterstützt), verwenden Sie Folgendes Methode. Es ist dasselbe, was die Bibliotheken tun, um DOM-Elemente aus einem HTML-String abzurufen ( mit etwas zusätzlicher Arbeit für den IE um Fehler mit der Implementierung von innerHTML zu umgehen):

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

Beachten Sie, dass im Gegensatz zu HTML-Vorlagen dieses für einige Elemente, die legal keine untergeordneten Elemente eines _<div>_ sein dürfen, wie z. B. _<td>_, nicht funktioniert .

Wenn Sie bereits eine Bibliothek verwenden, empfehlen wir Ihnen, sich an die von der Bibliothek genehmigte Methode zum Erstellen von Elementen aus HTML-Zeichenfolgen zu halten:

732
Crescent Fresh

In HTML 5 wurde das <template> -Element eingeführt, das für diesen Zweck verwendet werden kann (wie jetzt in den WhatWG-Spezifikation und MDN-Dokumente beschrieben).

Ein <template> ist ein HTML-Element, dem jeder andere Elementtyp als untergeordnetes Element erlaubt ist. Die template hat eine .content -Eigenschaft, auf die Sie mit JavaScript zugreifen können. Diese verweist auf ein DocumentFragment mit dem Inhalt der Vorlage. Dies bedeutet, dass Sie eine HTML-Zeichenfolge in DOM-Elemente konvertieren können, indem Sie innerHTML eines <template> -Elements festlegen und dann in die .content -Eigenschaft von template greifen.

Beispiele:

/**
 * @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>');

Beachten Sie, dass ähnliche Ansätze wie verwenden Sie ein anderes Containerelement wie div nicht ganz funktionieren. HTML hat Einschränkungen, welche Elementtypen in welchen anderen Elementtypen existieren dürfen. Beispielsweise können Sie td nicht als direktes untergeordnetes Element von div definieren. Dies führt dazu, dass diese Elemente verschwinden, wenn Sie versuchen, innerHTML eines div so festzulegen, dass es sie enthält. Da <template>s keine derartigen inhaltlichen Einschränkungen haben, gilt dieses Manko nicht bei Verwendung einer Vorlage.

template wird in einigen alten Browsern jedoch nicht unterstützt. Ab Januar 2018 Kann ich ... Schätzungen verwenden 90% der Benutzer weltweit verwenden einen Browser, der templates unterstützt . Insbesondere werden sie von keiner Version von Internet Explorer unterstützt. Microsoft hat die template-Unterstützung erst mit der Veröffentlichung von Edge implementiert.

Wenn Sie das Glück haben, Code zu schreiben, der sich nur an Benutzer in modernen Browsern richtet, können Sie ihn jetzt verwenden. Andernfalls müssen Sie möglicherweise eine Weile warten, bis die Benutzer auf dem Laufenden sind.

267
Mark Amery

Verwenden Sie insertAdjacentHTML () . Es funktioniert mit allen gängigen Browsern, auch mit IE11.

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

Neuere DOM-Implementierungen haben range.createContextualFragment , das auf rahmenunabhängige Weise das tut, was Sie wollen.

Es wird weitgehend unterstützt. Um sicherzugehen, überprüfen Sie die Kompatibilität in derselben MDN-Verknüpfung, da sie sich ändern wird. Ab Mai 2017 ist dies:

_Feature         Chrome   Edge   Firefox(Gecko)  Internet Explorer   Opera   Safari
Basic support   (Yes)    (Yes)  (Yes)           11                  15.0    9.1.2
_
26
kojiro

Es ist kein Tweak erforderlich, Sie haben eine native API:

const toNodes = html =>
    new DOMParser().parseFromString(html, 'text/html').body.childNodes
16
math2001

Hier ist eine einfache Möglichkeit, dies zu tun:

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);
15
william malo

Für bestimmte HTML-Fragmente wie <td>test</td>, div.innerHTML, DOMParser.parseFromString und range.createContextualFragment (ohne den richtigen Kontext), die hier in anderen Antworten erwähnt wurden, wird das <td> -Element nicht erstellt.

jQuery.parseHTML () behandelt sie ordnungsgemäß (ich extrahierte die parseHTML-Funktion von jQuery 2 in eine unabhängige Funktion , die in Nicht-jquery-Codebasen verwendet werden kann).

Wenn Sie nur Edge 13+ unterstützen, ist es einfacher, nur das HTML5-Vorlagentag zu verwenden:

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

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

Mit Prototype können Sie auch Folgendes tun:

HTML:

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

JS:

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

Sie können gültige DOM-Knoten aus einer Zeichenfolge erstellen, indem Sie Folgendes verwenden:

document.createRange().createContextualFragment()

Im folgenden Beispiel wird der Seite ein Schaltflächenelement hinzugefügt, das das Markup aus einer Zeichenfolge übernimmt:

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);
8
GibboK

Ich verwende diese Methode (Works in IE9 +), obwohl sie <td> oder einige andere ungültige direkte untergeordnete Elemente von body nicht analysiert:

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
usrbowe

Um das nützliche . ToDOM () - Snippet, das wir an verschiedenen Stellen finden, weiter zu verbessern, können wir jetzt sicher verwenden Backticks ( Template-Literale ).

Wir können also einfache und doppelte Anführungszeichen in der foo html-Deklaration verwenden.

Dies verhält sich wie Heredocs für diejenigen, die mit dem Begriff vertraut sind.

Dies kann mit Variablen erweitert werden, um komplexe Vorlagen zu erstellen:

Vorlagenliterale werden anstelle von doppelten oder einfachen Anführungszeichen durch das Back-Tick () -Zeichen (mit ernstem Akzent) eingeschlossen. Vorlagenliterale können Platzhalter enthalten. Diese sind durch das Dollarzeichen und geschweifte Klammern ($ {expression}) gekennzeichnet. Die Ausdrücke in den Platzhaltern und der Text dazwischen werden an eine Funktion übergeben. Die Standardfunktion verkettet die Teile nur zu einer einzigen Zeichenfolge. Befindet sich vor dem Vorlagenliteral (hier taggen) ein Ausdruck, spricht man von einer "getaggten Vorlage". In diesem Fall wird der Tag-Ausdruck (normalerweise eine Funktion) mit dem verarbeiteten Vorlagenliteral aufgerufen, das Sie dann vor der Ausgabe bearbeiten können. Um einen Back-Tick in einem Template-Literal zu umgehen, setzen Sie einen Backslash vor den Back-Tick.

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}

Warum also nicht direkt .innerHTML += verwenden? Dadurch wird das gesamte DOM vom Browser neu berechnet, es ist viel langsamer.

https://caniuse.com/template-literals

3
NVRM

Ich habe einen Document-Prototyp hinzugefügt, der ein Element aus einem String erstellt:

Document.prototype.createElementFromString = function (str) {
    const element = new DOMParser().parseFromString(str, 'text/html');
    const child = element.documentElement.querySelector('body').firstChild;
    return child;
};
3
Raza

Spät aber nur als Notiz;

Es ist möglich, dem Zielelement ein triviales Element als Container hinzuzufügen und es nach der Verwendung zu entfernen.

// Getestet auf chrome 23.0, Firefox 18.0, dh 7-8-9 und 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
K-Gun

HTML5 & ES6

<template>

Demo

"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>
1
xgqfrms-gildata

Hier ist mein Code und es funktioniert:

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

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

Zum Teufel dachte ich, ich würde diesen überkomplizierten, aber dennoch einfachen Ansatz teilen, den ich mir ausgedacht habe ... Vielleicht findet jemand etwas Nützliches.

/*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
JxAxMxIxN

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

0
nitish kumar