DocumentFragment: qu'est-ce que c'est et comment (pas) le combattre

Clause de non-responsabilité
Il semble que je commence une nouvelle série d'articles - un peu ennuyeux et purement utilitaire. Ils expliqueront les points qui causent souvent des difficultés à mes élèves. Si vous êtes un développeur Web chevronné, vous ne serez probablement pas intéressé. Si vous attendez des perversions au pouvoir de la JS de vendredi, elles ne seront hélas pas là.


DocumentFragment est une des choses que les étudiants ont régulièrement du mal à comprendre. En général, je ne peux pas leur en vouloir. Avec une simplicité externe, il possède plusieurs propriétés non évidentes et même contre-intuitives. Dans cet article, je veux rassembler tout ce qu'un débutant doit savoir sur lui.

image

Qu'est ce que c'est


Un DocumentFragment est un conteneur qui peut contenir un nombre arbitraire d'éléments DOM. Si tout simplement, vous pouvez l'imaginer comme un seau. Les éléments y sont empilés de sorte qu'au bon moment, ils puissent être immédiatement vidés.

Comment créer


Élémentaire.

var fragment = document.createDocumentFragment(); 

Il existe également d'autres moyens, mais à leur sujet ci-dessous.

Pourquoi ai-je besoin


Comme je l'ai écrit ci-dessus, afin de stocker des éléments DOM. "Mais ils peuvent être stockés dans une diva ordinaire", peut objecter le lecteur. Certes, cependant, le fragment a une propriété unique qui en fait le meilleur candidat pour ce rôle. Considérez le code suivant:

 var fragment = document.createDocumentFragment(); var parentDiv = document.createElement("div"); var div1 = document.createElement("div"); var div2 = document.createElement("div"); fragment.appendChild(div1); fragment.appendChild(div2); //   parentDiv.appendChild(fragment); console.log(parentDiv.children); 

Que nous dira la console? Une personne peu familière avec DocumentFragment pourrait penser que parentDiv aura un enfant - fragment . Mais en fait, il aura deux enfants - div1 et div2 . Le fait est que le fragment lui-même n'est pas un élément DOM, c'est seulement un conteneur pour les éléments DOM. Et quand il est passé en argument à des méthodes comme appendChild ou insertBefore , il ne s'intègre pas dans l'arborescence DOM, mais y incorpore son contenu.

Mais pourquoi en avez-vous besoin?


La propriété «bucket» est, bien sûr, bonne, mais en quoi est-elle utile en pratique? DocumentFragment a deux principaux domaines d'application.

1. Stockage de morceaux de HTML qui n'ont pas d'ancêtre commun.

Il y a des situations où nous devons remplacer le contenu d'un élément, mais ne touchez pas l'élément lui-même. Supposons que nous utilisons la délégation d'événements et que tous les gestionnaires d'événements qui se produisent sur des éléments internes soient suspendus sur un div externe. Dans ce cas, DocumentFragment est idéal pour nous:

 div.innerHTML = ""; div.appendChild(fragmentWithAllContent); 

"Mais pouvons-nous simplement ajouter des éléments à la div dès que nous les créons?" - demandera le lecteur corrosif. Nous pouvons, mais cela n'en vaut pas la peine, et c'est pourquoi.

2. Amélioration des performances dans le cas d'inserts multiples.

Le fait est que chaque fois que nous changeons quelque chose dans l'arborescence DOM active, le navigateur doit faire un tas de calculs. Vous pouvez en savoir plus à ce sujet ici , par exemple. Dans cet article, nous nous limitons à mentionner qu'il y a une telle bête terrible - refusion. Lorsque nous ajoutons un élément à la page, cette bête se réveille et mange un morceau de temps processeur. Si nous ajoutons cent éléments à tour de rôle, la bête se réveillera cent fois et fera une piqûre cent fois. Pour l'utilisateur, cela peut déjà être un «gel» assez visible.

Lorsque nous ajoutons un élément à DocumentFragment, cela ne provoque pas de redistribution, car le fragment ne fait pas (et ne peut fondamentalement pas) faire partie de l'arborescence DOM active. Et le plus important: lorsque nous insérons le contenu d'un fragment à l'aide d' appendChild ou d'autres méthodes similaires, quel que soit le nombre d'éléments à l'intérieur du fragment, la redistribution n'est appelée qu'une seule fois .

Pour plus de clarté, j'ai fait une référence simple afin que le lecteur puisse personnellement voir la différence.

Mise à jour: le camarade nuit a dit que pour Chrome moderne, mes mots ne sont plus vrais. Dans ce document, la redistribution n'est pas exécutée plus tôt que nécessaire, et grâce à cela, le code sans DocumentFragment fonctionne réellement plus rapidement , et avec d'autres navigateurs, ce n'est pas si évident. Donc, avant de décider d'utiliser des fragments, vous avez besoin d'un profilage et d'une recherche sur le public cible du site.

Nuances


Il existe deux fonctionnalités qui rendent les novices souvent difficiles à utiliser des fragments. Premièrement: comme je l'ai écrit ci-dessus, un fragment n'est pas un élément DOM . Cela signifie qu'il lui manque de nombreuses méthodes et propriétés familières, en particulier - innerHTML . Par conséquent, vous ne pouvez pas simplement transformer une chaîne en contenu d'un fragment. Comment faire cela n'est pas facile, sera décrit ci-dessous.

La deuxième caractéristique: le fragment lors de l'utilisation de "butin". Plus précisément, il est vidé. Lorsque nous div.appendChild(fragment) , tous les enfants du fragment sont div.appendChild(fragment) dans un div . Et puisqu'un élément ne peut pas avoir plus d'un parent, cela signifie qu'ils sont supprimés du fragment! Pour éviter ce comportement lorsqu'il n'est pas souhaitable, vous pouvez utiliser cloneNode .

balise <template>


Il existe un endroit où vous pouvez rencontrer DocumentFragment sans le créer via JS. Il s'agit de la propriété de content de l'élément de modèle.

La <template> inventée spécifiquement pour stocker des morceaux de code HTML, mais pas pour charger le navigateur à l'avance. Ce qui se trouve à l'intérieur de cette balise ne fait pas partie de l'arborescence DOM active. En particulier (les nouveaux arrivants rencontrent souvent cela aussi), ils ne peuvent pas être trouvés en utilisant querySelector . Les éléments créés à partir de code HTML à l'intérieur de la <template> n'en deviennent pas des enfants. Au lieu de cela, JavaScript peut y accéder via la propriété de content , ce qui est - une surprise! - juste DocumentFragment.

À l'aide de l'élément de modèle, vous pouvez créer un fragment à partir d'une chaîne:

 function createFragmentFromString(str){ var template = document.createElement("template"); template.innerHTML = str; return template.content; } 

Épilogue


Si vous êtes nouveau dans le développement Web, j'espère que vous avez beaucoup appris. Si vous êtes un développeur expérimenté, vous voudrez peut-être compléter cet article avec quelque chose, auquel cas n'hésitez pas à en parler dans les commentaires. Merci d'avoir lu et bonne journée.

Source: https://habr.com/ru/post/fr413287/


All Articles