Je sais que en ajoutant innerHTML
aux fragments de document a récemment été discuté et que nous espérons l'inclure dans la norme DOM Mais, quelle est la solution de contournement que vous êtes censé utiliser entre-temps?
C'est, prenez
var html = '<div>x</div><span>y</span>';
var frag = document.createDocumentFragment();
Je veux à la fois la div
et la span
à l'intérieur de frag
, avec une ligne simple.
Points bonus pour pas de boucles. jQuery est autorisé, mais j'ai déjà essayé $(html).appendTo(frag)
; frag
est toujours vide par la suite.
Voici un moyen dans les navigateurs modernes sans bouclage:
var temp = document.createElement('template');
temp.innerHTML = '<div>x</div><span>y</span>';
var frag = temp.content;
ou, en tant que réutilisable
function fragmentFromString(strHTML) {
var temp = document.createElement('template');
temp.innerHTML = strHTML;
return temp.content;
}
UPDATE: J'ai trouvé un moyen plus simple d'utiliser l'idée principale de Pete, qui ajoute IE11 au mélange:
function fragmentFromString(strHTML) {
return document.createRange().createContextualFragment(strHTML);
}
La couverture est meilleure que la méthode <template>
et a été testée dans IE11, Ch, FF.
Live test/démo disponible http://pagedemos.com/str2fragment/
Actuellement, la seule façon de remplir un fragment de document en utilisant uniquement une chaîne est de créer un objet temporaire et de parcourir les enfants pour les ajouter au fragment.
Si vous souhaitez créer un document entier, utilisez plutôt DOMParser. Regardez cette réponse .
Code:
var frag = document.createDocumentFragment(),
tmp = document.createElement('body'), child;
tmp.innerHTML = '<div>x</div><span>y</span>';
while (child = tmp.firstElementChild) {
frag.appendChild(child);
}
Une ligne (deux lignes pour la lisibilité) (entrée: String html
, sortie: DocumentFragment frag
):
var frag =document.createDocumentFragment(), t=document.createElement('body'), c;
t.innerHTML = html; while(c=t.firstElementChild) frag.appendChild(c);
Utilisez 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);
Notez que les principales différences entre cette approche et l'approche <template>
sont les suivantes:
Range.createContextualFragment est un peu plus largement supporté (IE11 vient de le recevoir, Safari, Chrome et FF le sont depuis un moment).
Les éléments personnalisés au sein du code HTML seront immédiatement mis à niveau avec la plage, mais uniquement lorsqu'ils sont clonés dans le document réel avec modèle. L’approche par modèle est un peu plus «inerte», ce qui peut être souhaitable.
@PAEz a souligné que l'approche de @ RobW n'inclut pas text between elements. En effet, children
ne récupère que Eléments , et non Nœuds . Une approche plus robuste pourrait être la suivante:
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]);
}
Les performances peuvent pâtir de l'utilisation de gros morceaux de HTML, mais il est compatible avec la plupart des navigateurs plus anciens et concis.
createDocumentFragment crée un "conteneur" DOM vide. innerHtml et d'autres méthodes ne fonctionnent que sur les nœuds DOM (pas le conteneur). Vous devez donc d'abord créer vos nœuds, puis les ajouter au fragment. Vous pouvez le faire en utilisant une méthode pénible d’appendChild ou vous pouvez créer un nœud, le modifier innerHtml et l’ajouter à votre fragment.
var frag = document.createDocumentFragment();
var html = '<div>x</div><span>y</span>';
var holder = document.createElement("div")
holder.innerHTML = html
frag.appendChild(holder)
avec jQuery, vous conservez simplement et construisez votre code HTML en tant que chaîne. Si vous voulez le convertir en un objet jQuery pour y effectuer des opérations similaires, faites simplement $ (html) qui crée un objet JQuery en mémoire. Une fois que vous êtes prêt à l'ajouter, vous l'ajoutez simplement à un élément existant d'une page.
Voici une solution x-browser, testée sur IE10, IE11, Edge, Chrome et 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; } }
Comme @dandavis a dit, il existe une méthode standard en utilisant le template-tag.
Mais si vous aimez supporter IE11 et que vous devez analyser des éléments de table tels que '<td> test', vous pouvez utiliser cette fonction:
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;
}
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);
Pour ce faire avec le moins de lignes possible, vous pouvez envelopper votre contenu ci-dessus dans une autre division afin de ne pas avoir à faire une boucle ou à appeler appendchild plus d'une fois. En utilisant jQuery (comme vous l’avez indiqué, c’est autorisé), vous pouvez très rapidement créer un nœud dom non attaché et le placer dans le fragment.
var html = '<div id="main"><div>x</div><span>y</span></div>';
var frag = document.createDocumentFragment();
frag.appendChild($(html)[0]);