Создание нового элемента DOM из строки HTML с использованием встроенных методов DOM или Prototype

У меня есть HTML-строка, представляющая элемент: '<li>text</li>'. Я хотел бы добавить его к элементу в DOM (ul в моем случае). Как я могу сделать это с помощью Prototype или DOM?

(Я знаю, что мог бы легко это сделать в jQuery, но, к сожалению, мы не используем jQuery.)

Ответ 1

Примечание: большинство современных браузеров поддерживают элементы HTML <template>, которые обеспечивают более надежный способ превращения создания элементов из строк. См. Ответ Марк Амери ниже для деталей.

Для более старых браузеров и для node/jsdom: (который еще не поддерживает элементы <template> на момент написания) используйте следующий метод. Это то же самое, что библиотеки используют для получения элементов DOM из строки HTML (с некоторой дополнительной работой для 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:

Ответ 2

В HTML 5 появился элемент <template> который можно использовать для этой цели (как теперь описано в спецификации WhatWG и документах MDN).

<template> - это HTML-элемент, которому разрешен любой другой тип элемента в качестве дочернего. template имеет свойство .content, доступ к которому можно получить с помощью JavaScript, который указывает на DocumentFragment с содержимым шаблона. Это означает, что вы можете преобразовать строку HTML в элементы DOM, установив innerHTML элемента <template>, а затем .content свойство 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 г. Можно ли использовать... по оценкам, 90% пользователей во всем мире используют браузер, который поддерживает template. В частности, ни одна версия Internet Explorer не поддерживает их; Microsoft не реализовала поддержку template до выпуска Edge.

Если вам повезло, что вы пишете код, предназначенный только для пользователей в современных браузерах, используйте его прямо сейчас. В противном случае вам может потребоваться некоторое время, чтобы пользователи наверстали упущенное.

Ответ 3

Используйте insertAdjacentHTML(). Он работает со всеми современными браузерами, даже с IE11.

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

Ответ 4

Более новые реализации DOM имеют range.createContextualFragment, который делает то, что вы хотите, независимо от фреймворка.

Это широко поддерживается. Однако, чтобы быть уверенным, проверьте его совместимость в той же ссылке MDN, поскольку она будет меняться. По состоянию на май 2017 года это так:

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

Ответ 5

Нет необходимости в настройках, у вас есть собственный API:

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

Ответ 6

Вот простой способ сделать это:

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

Ответ 7

Для некоторых фрагментов HTML, таких как <td>test</td>, div.innerHTML, DOMParser.parseFromString и range.createContextualFragment (без правильного контекста), упомянутых в других ответах здесь, не будет создаваться элемент <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>');

Ответ 8

С Prototype вы также можете сделать:

HTML:

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

JS:

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

Ответ 9

Вы можете создать допустимые узлы 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);

Ответ 10

Я использую этот метод (работает в 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>

Ответ 11

Я добавил прототип Document, который создает элемент из строки:

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

Ответ 12

Позднее, но как примечание;

Можно добавить тривиальный элемент к целевому элементу в качестве контейнера и удалить его после использования.

//Проверено на chrome 23.0, firefox 18.0, т.е. 7-8-9 и опера 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>

Ответ 13

Кроме того, для улучшения полезного фрагмента .toDOM(), который мы можем найти в разных местах, теперь мы можем безопасно использовать обратные ссылки (литералы шаблона).

Таким образом, мы можем иметь одинарные и двойные кавычки в объявлении foo html.

Это ведет себя как heredocs для тех, кто знаком с этим термином.

Это может быть улучшено с помощью переменных, чтобы сделать сложные шаблоны:

Шаблонные литералы заключены в обратную галочку () (серьезный акцент) вместо двойных или одинарных кавычек. Шаблонные литералы могут содержать заполнители. Они обозначены знаком доллара и фигурными скобками ($ {выражение}). Выражения в заполнителях и текст между ними передаются в функцию. Функция по умолчанию просто объединяет части в одну строку. Если перед литералом шаблона есть выражение (здесь тег), это называется "теговым шаблоном". В этом случае выражение тега (обычно функция) вызывается с обработанным литералом шаблона, которым вы можете манипулировать перед выводом. Чтобы избежать обратной галочки в литерале шаблона, поставьте обратную косую черту\перед обратной галочкой.

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}

Ответ 14

Здесь мой код, и он работает:

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

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

Ответ 15

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>

Ответ 16

Для этого я подумал, что поделюсь этим сложным, но тем не менее простым подходом, который я придумал... Может быть, кто-то найдет что-то полезное.

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

Ответ 17

Вы можете попробовать dom-builder для создания элементов html из вашего js-кода

Ответ 18

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

Ответ 19

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

Ответ 20

Вот рабочий код для меня

Я хотел преобразовать текстовую строку в элемент HTML

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

Ответ 21

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

Используйте jnerator

Ответ 22

Если ваш javascript опирается на jQuery, используйте append. Пример:

$('[data-label="tid_0"]').append('<datalist id="strikes"><option>a</option><option>10d</option><option>30d</option><option>30f</option></datalist>');

Соответствующий jQuery API

Ответ 23

Вы можете использовать следующую функцию для преобразования текста "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);

Ответ 24

Это тоже будет работать:

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

Он больше похож на jQuery с цепочками вызовов функций.