Создание нового элемента 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 с цепочками вызовов функций.