Вставка произвольного HTML в DocumentFragment
Я знаю, что добавление innerHTML
для документирования фрагментов было недавно обсуждено, и мы надеемся увидеть включение в DOM Standard. Но каково обходное решение, которое вы должны использовать в это время?
То есть возьмите
var html = '<div>x</div><span>y</span>';
var frag = document.createDocumentFragment();
Я хочу как div
, так и span
внутри frag
, с простым однострочным.
Бонусные баллы за отсутствие петель. jQuery разрешен, но я уже пробовал $(html).appendTo(frag)
; frag
по-прежнему остается пустым.
Ответы
Ответ 1
Вот в современных браузерах без цикла:
var temp = document.createElement('template');
temp.innerHTML = '<div>x</div><span>y</span>';
var frag = temp.content;
или, как повторно используемый
function fragmentFromString(strHTML) {
var temp = document.createElement('template');
temp.innerHTML = strHTML;
return temp.content;
}
UPDATE:
Я нашел более простой способ использовать основную идею Пита, которая добавляет IE11 в микс:
function fragmentFromString(strHTML) {
return document.createRange().createContextualFragment(strHTML);
}
Покрытие лучше, чем метод <template>
и проверено в IE11, Ch, FF.
Live test/demo available http://pagedemos.com/str2fragment/
Ответ 2
В настоящее время единственным способом заполнить фрагмент документа, используя только строку, является создание временного объекта и цикл через дочерние элементы, чтобы добавить их в фрагмент.
- Поскольку он не добавлен к документу, ничего не отображается, поэтому нет производительности.
- Вы видите цикл, но он пробивает только первые дочерние элементы. В большинстве документов есть только несколько полукорневых элементов, так что это тоже не очень важно.
Если вы хотите создать целый документ, вместо этого используйте DOMParser. Посмотрите этот ответ.
код:
var frag = document.createDocumentFragment(),
tmp = document.createElement('body'), child;
tmp.innerHTML = '<div>x</div><span>y</span>';
while (child = tmp.firstElementChild) {
frag.appendChild(child);
}
Однострочный (две строки для удобочитаемости) (ввод: String html
, вывод: DocumentFragment frag
):
var frag =document.createDocumentFragment(), t=document.createElement('body'), c;
t.innerHTML = html; while(c=t.firstElementChild) frag.appendChild(c);
Ответ 3
Используйте Range.createContextualFragment:
var html = '<div>x</div><span>y</span>';
var range = document.createRange();
// or whatever context the fragment is to be evaluated in.
var parseContext = document.body;
range.selectNodeContents(parseContext);
var fragment = range.createContextualFragment(html);
Обратите внимание, что основные различия между этим подходом и подходом <template>
заключаются в следующем:
-
Range.createContextualFragment немного более широко поддерживается (IE11 только что получил его, Safari, Chrome и FF на некоторое время).
-
Пользовательские элементы в HTML будут немедленно обновлены диапазоном, но только при клонировании в настоящий документ с шаблоном. Шаблонный подход является немного более "инертным", что может быть желательным.
Ответ 4
@PAEz указал, что подход @RobW не включает текст между элементами. Это потому, что children
захватывает только элементы, а не узлы. Более надежный подход может быть следующим:
var fragment = document.createDocumentFragment(),
intermediateContainer = document.createElement('div');
intermediateContainer.innerHTML = "Wubba<div>Lubba</div>Dub<span>Dub</span>";
while (intermediateContainer.childNodes.length > 0) {
fragment.appendChild(intermediateContainer.childNodes[0]);
}
Производительность может пострадать от больших фрагментов HTML, однако она совместима со многими старыми браузерами и кратким.
Ответ 5
createDocumentFragment создает пустой контейнер DOM. innerHtml, а другие методы работают только с узлами DOM (а не с контейнером), поэтому вам сначала нужно создать свои узлы, а затем добавить их в фрагмент. Вы можете сделать это, используя болезненный метод appendChild или можете создать один node и изменить его innerHtml и добавить его в свой фрагмент.
var frag = document.createDocumentFragment();
var html = '<div>x</div><span>y</span>';
var holder = document.createElement("div")
holder.innerHTML = html
frag.appendChild(holder)
с jquery вы просто держите и создаете свой html в виде строки. Если вы хотите преобразовать его в объект jquery для выполнения jquery, как операции на нем, просто сделайте $(html), который создает объект jquery в памяти. Когда вы будете готовы добавить его, вы просто добавите его к существующему элементу на странице
Ответ 6
Как и @dandavis, существует стандартный способ использования шаблона-тега.
Но если вам нравится поддерживать IE11, и вам нужно проанализировать элементы таблицы, такие как "<td> test", вы можете использовать эту функцию:
function createFragment(html){
var tmpl = document.createElement('template');
tmpl.innerHTML = html;
if (tmpl.content == void 0){ // ie11
var fragment = document.createDocumentFragment();
var isTableEl = /^[^\S]*?<(t(?:head|body|foot|r|d|h))/i.test(html);
tmpl.innerHTML = isTableEl ? '<table>'+html : html;
var els = isTableEl ? tmpl.querySelector(RegExp.$1).parentNode.childNodes : tmpl.childNodes;
while(els[0]) fragment.appendChild(els[0]);
return fragment;
}
return tmpl.content;
}
Ответ 7
Вот x-браузерное решение, протестированное на IE10, IE11, Edge, Chrome и FF.
function HTML2DocumentFragment(markup: string) {
if (markup.toLowerCase().trim().indexOf('<!doctype') === 0) {
let doc = document.implementation.createHTMLDocument("");
doc.documentElement.innerHTML = markup;
return doc;
} else if ('content' in document.createElement('template')) {
// Template tag exists!
let el = document.createElement('template');
el.innerHTML = markup;
return el.content;
} else {
// Template tag doesn't exist!
var docfrag = document.createDocumentFragment();
let el = document.createElement('body');
el.innerHTML = markup;
for (let i = 0; 0 < el.childNodes.length;) {
docfrag.appendChild(el.childNodes[i]);
}
return docfrag;
}
}
Ответ 8
Чтобы сделать это с минимальными строками, вы можете обернуть свой контент выше в другом div, чтобы вам не приходилось цитировать или вызывать appendchild более одного раза. Использование jQuery (как вы сказали, разрешено), вы можете очень быстро создать непривязанный dom node и поместить его в фрагмент.
var html = '<div id="main"><div>x</div><span>y</span></div>';
var frag = document.createDocumentFragment();
frag.appendChild($(html)[0]);
Ответ 9
var html = '<div>x</div><span>y</span>';
var frag = document.createDocumentFragment();
var e = document.createElement('i');
frag.appendChild(e);
e.insertAdjacentHTML('afterend', html);
frag.removeChild(e);
Ответ 10
Никто никогда не предоставлял запрошенную "легкую однострочку".
Учитывая переменные...
var html = '<div>x</div><span>y</span>';
var frag = document.createDocumentFragment();
… Следующая строка поможет (в Firefox 67.0.4):
frag.append(...new DOMParser().parseFromString(html, "text/html").body.childNodes);