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

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

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

21 ответов


Примечание: большинство современных браузеров поддерживают 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-строк:


HTML 5 представил <template> элемент, который может быть использован для этой цели (как сейчас описано в WHATWG spec и MDN docs).

A <template> - это HTML-элемент, которому разрешен любой другой тип элемента в качестве дочернего. The template есть .content свойство, которое вы можете получить доступ с помощью JavaScript, который указывает на DocumentFragment с содержимым шаблона. Это означает, что вы можете преобразовать строку HTML в элементы DOM, установив innerHTML of a <template> элемент, а затем до template ' s .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 of a div чтобы содержать их. С <template>s не имеют таких ограничений на свой контент, этот недостаток не применяется при использовании шаблона.

, template не поддерживается в некоторых старых браузерах. По состоянию на январь 2018 года,могу ли я использовать... смета 90% пользователей по всему миру используют браузер, который поддерживает templates. В частности, ни одна версия Internet Explorer не поддерживает их; Microsoft не реализовала template поддержка до выпуска Edge.

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


новые реализации 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

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

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

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

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

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

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

С прототипом вы также можете сделать:

HTML-код:

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

JS:

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

для определенных фрагментов html, таких как <td>test</td>, div.innerHTML, DOMParser.parseFromString и диапазон.createContextualFragment (без правильного контекста) не создаст <td> элемент.

С помощью jQuery.parseHTML (), обрабатывает их (я извлек функция parseHTML jQuery 2 в независимый gist).

для Edge 13+, используйте тег шаблона:

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

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

вы можете создать допустимые узлы DOM из строки, используя:

document.createRange().createContextualFragment()

в следующем примере добавляется элемент button на странице, берущий разметку из строки:

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

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

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

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

вот мой код, и он работает:

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

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

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

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

/ / протестировано на chrome 23.0, firefox 18.0, ie 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>

в HTML5 & ES6

демо

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

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

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

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

Итак, мы можем иметь одинарные и двойные кавычки в фу объявление html.

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

Это можно увеличить furthermore с переменными, для того чтобы сделать сложные шаблоны:

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

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}

https://caniuse.com/template-literals


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

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

Я хотел, чтобы преобразовать 'текст ' string to HTML element

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

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

использовать jnerator


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

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

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

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