web-dev-qa-db-fra.com

en utilisant document.createDocumentFragment () et innerHTML pour manipuler un DOM

Je crée un fragment de document comme suit:

var aWholeHTMLDocument = '<!doctype html> <html><head></head><body><h1>hello world</h1></body></html>';
var frag = document.createDocumentFragment();
frag.innerHTML = aWholeHTMLDocument;

La variable aWholeHTMLDocument contient une longue chaîne qui est le document html entier d'une page, et je veux l'insérer dans mon fragment afin de générer et de manipuler le DOM dynamiquement.

Ma question est, une fois que j'ai ajouté cette chaîne à frag.innerHTML, ne devrait-il pas charger cette chaîne et la convertir en objet DOM?

Après avoir défini innerHTML, ne devrais-je pas avoir accès au DOM via une propriété?

J'ai essayé frag.childNodes mais il ne semble rien contenir, et tout ce que je veux, c'est simplement accéder à ce DOM nouvellement créé.

35
Loic Duros

Vous ne pouvez pas définir le innerHTML d'un fragment de document comme vous le feriez avec un nœud normal, c'est le problème. Ajouter une div standard et définir le innerHTML de cela est la solution courante.

28
Johan

Alors que DocumentFragment ne prend pas en charge innerHTML, <template> le fait .

La propriété content d'un élément <template> Est un DocumentFragment donc elle se comporte de la même manière. Par exemple, vous pouvez faire:

var tpl = document.createElement('template');
tpl.innerHTML = '<tr><td>Hello</td><td>world</td></tr>';
document.querySelector('table').appendChild(tpl.content);

L'exemple ci-dessus est important car vous ne pouvez pas le faire avec innerHTML et par exemple un <div>, car un <div> n'autorise pas les éléments <tr> en tant qu'enfants.


REMARQUE: Un DocumentFragment supprimera toujours les balises <head> Et <body>, Il ne fera donc pas ce que vous voulez non plus. Vous devez vraiment créer un tout nouveau Document.

26
chowey

Je sais que cette question est ancienne, mais j'ai rencontré le même problème en jouant avec un fragment de document parce que je ne savais pas que je devais y ajouter un div et utiliser le innerHTML du div pour charger des chaînes de HTML et en obtenir des éléments DOM. J'ai d'autres réponses sur la façon de faire ce genre de chose, mieux adapté aux documents entiers .

Dans firefox (23.0.1), il semble que la définition de la propriété innerHTML du fragment de document ne génère pas automatiquement les éléments. Ce n'est qu'après avoir ajouté le fragment au document que les éléments sont créés.

Pour créer un document entier , utilisez les méthodes document.implementation si elles sont prises en charge. J'ai réussi à le faire sur Firefox, mais je ne l'ai pas vraiment testé sur d'autres navigateurs. Vous pouvez consulter HTMLParser.js dans la boîte à outils AtropaTool pour un exemple d'utilisation des méthodes document.implementation. J'ai utilisé ce morceau de script pour XMLHttpRequest pages et les manipuler ou en extraire des données. Les scripts de la page ne sont pas exécutés cependant, c'est ce que je voulais, mais ce n'est peut-être pas ce que vous voulez. La raison pour laquelle je suis allé avec cette méthode plutôt verbeuse au lieu d'essayer d'utiliser directement l'analyse disponible à partir de l'objet XMLHttpRequest était que j'ai rencontré pas mal de problèmes avec les erreurs d'analyse à l'époque et je voulais spécifier que le doc devrait être analysé comme HTML 4 Transitional car il semble prendre toutes sortes de slop et produire un DOM.

Il existe également un DOMParser qui peut être plus facile à utiliser. Il y a une implémentation par Eli Gray sur la page de MDN pour les navigateurs qui n'ont pas le DOMParser mais qui supportent document.implementation.createHTMLDocument. Les spécifications de DOMParser spécifient que les scripts de la page ne sont pas exécutés et le contenu des balises noscript rendu.

Si vous avez vraiment besoin de scripts activés dans la page, vous pouvez créer un iFrame avec 0 hauteur, 0 largeur, pas de bordures, etc. Il serait toujours dans la page mais vous pourriez le cacher assez bien.

Il y a aussi la possibilité d'utiliser window.open() avec document.write, Les méthodes DOM ou ce que vous voulez. Certains navigateurs vous permettent même de faire des URI de données maintenant.

var x = window.open( 'data:text/html;base64,' + btoa('<h1>hi</h1>') );
// wait for the document to load. It only takes a few milliseconds
// but we'll wait for 5 seconds so you can watch the child window
// change.
setTimeout(function () {
    console.log(x.document.documentElement.outerHTML);
    x.console.log('this is the console in the child window');
    x.document.body.innerHTML = 'oh wow';
}, 5000);

Ainsi, vous avez quelques options pour créer des documents entiers hors écran/masqués et les manipuler, qui prennent tous en charge le chargement du document à partir de chaînes.

Il y a aussi phantomjs , un projet génial produisant un navigateur web scriptable sans tête basé sur webkit. Vous aurez accès au système de fichiers local et pourrez faire à peu près tout ce que vous voulez. Je ne sais pas vraiment ce que vous essayez d'accomplir avec vos scripts et manipulations en pleine page.

5
Kastor

DocumentFragment hérite de Node , mais pas de Element qui contient le .innerHTML propriété.

Dans votre cas, j'utiliserais le <template> tag. In hérite de Element et il a un astucieux HTMLTemplateElement.content propriété qui vous donne un DocumentFragment.

Voici une méthode d'aide simple que vous pouvez utiliser:

export default function StringToFragment(string) {
    var renderer = document.createElement('template');
    renderer.innerHTML = string;
    return renderer.content;
}
5
pekaaw

Pour un module complémentaire Firefox, il est probablement plus logique d'utiliser document.implementation.createHTMLDocument , puis passez du DOM qui vous donne.

2
Gijs

Avec un fragment de document, vous ajouteriez des éléments que vous aviez créés avec document.createElement('yourElement'). aWholeHTMLDocument est simplement du texte. De plus, à moins que vous n'utilisiez des cadres, je ne sais pas pourquoi vous auriez besoin de créer tout le document HTML, utilisez simplement ce qui se trouve à l'intérieur des balises <body>.

1
qw3n

Utilisez appendChild

voir https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment

var fragment = document.createDocumentFragment();
... fragment.appendChild(some element);
document.querySelector('blah').appendChild(fragment);
0
Tony Jin