Создание нового элемента DOM из строки HTML с помощью встроенных методов DOM или прототипа
У меня есть строка HTML, представляющая элемент:'<li>text</li>'
. Я хотел бы добавить его к элементу в DOM (a ul
в моем случае). Как я могу сделать это с помощью прототипа или методов 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:
- прототип имеет эту функцию, встроенную в его
update()
метод.- jQuery реализовал его в своем
jQuery(html)
иjQuery.parseHTML
методы.
HTML 5 ввел
<template>
элемент, который может быть использован для этой цели (как сейчас описано в WHATWG spec и MDN docs).A
<template>
- это HTML-элемент, который может иметь любой другой тип элемента в качестве дочернего. Элементtemplate
есть.content
свойство, к которому вы можете получить доступ с помощью JavaScript, которое указывает наDocumentFragment
с содержимым шаблона. Это означает, что вы можете преобразовать строку HTML в элементы DOM, установивinnerHTML
на<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
наdiv
чтобы содержать их. Так как<template>
s не имеют таких ограничений на их содержание, этот недостаток не применяется при использовании шаблона.template
не поддерживается в некоторых старых браузерах. По состоянию на январь 2018 года,могу я использовать... смета 90% пользователей по всему миру используют браузер, который поддерживаетtemplate
s. В частности, ни одна версия Internet Explorer не поддерживает их; Microsoft не реализовалаtemplate
поддержка до выпуска края.Если вам посчастливилось писать код, предназначенный только для пользователей в современных браузерах, используйте их прямо сейчас. В противном случае, возможно, придется подождать некоторое время для пользователей, чтобы догнать.
новые реализации 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')" }));
для повышения кроме того, полезным .toDOM () фрагмент, который мы можем найти в разных местах, теперь мы можем безопасное использовать backticks (шаблон литералы).
Итак, мы можем иметь одинарные и двойные кавычки в фу html объявление.
Это вести себя как heredocs для тех, кто знаком с термином.
Это можно увеличить furthermore с переменными, для того чтобы сделать сложные шаблоны:
литералы шаблона заключаются в обратную галочку (
) (Гравис) символ вместо двойных или одинарных кавычек. Литералы шаблона могут содержат заполнители. Они обозначаются знаком доллара и фигурными фигурные скобки (${выражение}). Выражения в заполнителях и текст между ними передается в функцию. Функция по умолчанию просто объединяет части в одну строку. Если есть выражение перед литералом шаблона (тег здесь) это называется " 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}
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