Подтвердить что ты не робот

Вставка произвольного 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 по-прежнему остается пустым.

4b9b3361

Ответ 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);