


Comment écrire votre propre DOM virtuel ? Présentation de la méthode
Pour créer votre propre DOM virtuel, vous devez savoir deux choses. Vous n'avez même pas besoin de fouiller dans le code source de React ou de toute autre implémentation du DOM virtuel car ils sont si volumineux et complexes - mais en fait, la partie principale du DOM virtuel ne prend que moins de 50 lignes de code.
Il existe deux concepts :
- Le DOM virtuel est une cartographie du DOM réel
- Lorsque certains nœuds de l'arborescence du DOM virtuel changent, vous obtenez un nouvel arbre virtuel. L'algorithme compare les deux arbres (nouveau et ancien), trouve les différences, puis apporte simplement les modifications correspondantes sur le vrai DOM.
Simuler l'arborescence DOM avec des objets JS
Tout d'abord, nous devons stocker l'arborescence DOM en mémoire d'une manière ou d'une autre. Cela peut être fait en utilisant des objets JS normaux. Supposons que nous ayons un arbre comme celui-ci :
- item 1
- item 2
Ça a l'air simple, non ? Comment le représenter avec un objet JS ?
{ type: ‘ul’, props: { ‘class’: ‘list’ }, children: [ { type: ‘li’, props: {}, children: [‘item 1’] }, { type: ‘li’, props: {}, children: [‘item 2’] } ] }
Il y a deux choses à noter ici :
- Utilisez les objets suivants pour représenter les éléments DOM
{ type: ‘…’, props: { … }, children: [ … ] }
- Utilisez des chaînes JS ordinaires pour représenter les nœuds de texte DOM
Mais il y a beaucoup de contenu exprimé de cette façon, les arbres Dom sont assez difficiles. Écrivons ici une fonction auxiliaire pour faciliter la compréhension :
function h(type, props, …children) { return { type, props, children }; }
Utilisez cette méthode pour réorganiser le code initial :
h(‘ul’, { ‘class’: ‘list’ }, h(‘li’, {}, ‘item 1’), h(‘li’, {}, ‘item 2’), );
Cela semble beaucoup plus simple et vous pouvez aller plus loin. JSX est utilisé ici, comme suit :
- item 1
- item 2
est compilé en :
React.createElement(‘ul’, { className: ‘list’ }, React.createElement(‘li’, {}, ‘item 1’), React.createElement(‘li’, {}, ‘item 2’), );
Cela vous semble-t-il familier ? Si nous pouvons remplacer h(...)
par la fonction React.createElement(…)
que nous venons de définir, alors nous pouvons également utiliser la syntaxe JSX. En fait, il vous suffit d'ajouter ce commentaire en tête du fichier source :
/** @jsx h */
- item 1
- item 2
Il dit en fait à Babel 'Hé, petit frère, aide-moi à compiler la syntaxe JSX et à utiliser le h(...)
fonctionne à la place React.createElement(…)
, puis Babel commence à compiler. '
Pour résumer, on écrit le DOM comme ceci :
/** @jsx h */ const a = (
- item 1
- item 2
Babel va nous aider à le compiler en code comme ceci :
const a = ( h(‘ul’, { className: ‘list’ }, h(‘li’, {}, ‘item 1’), h(‘li’, {}, ‘item 2’), ); );
Quand la fonction “h”
est exécuté, il renverra un objet JS normal - c'est-à-dire notre DOM virtuel :
const a = ( { type: ‘ul’, props: { className: ‘list’ }, children: [ { type: ‘li’, props: {}, children: [‘item 1’] }, { type: ‘li’, props: {}, children: [‘item 2’] } ] } );
mappe du DOM virtuel au DOM réel
D'accord, nous avons maintenant l'arborescence DOM, représentée par un objet JS normal , Et notre propre structure. C'est cool, mais nous devons en créer un véritable DOM.
Faisons d'abord quelques hypothèses et déclarons quelques termes :
- Utilisons des variables commençant par '
$
' pour représenter de vrais nœuds DOM (éléments, nœuds de texte), donc $ parent le fera être un véritable élément DOM - DOM virtuel représenté par une variable nommée
node
* Tout comme dans React, il ne peut y avoir qu'un seul nœud racine - —Tous les autres nœuds sont à l'intérieur
Alors, écrivons une fonction createElement(…)
qui obtiendra un nœud DOM virtuel et renverra un nœud DOM réel. Ignorez les attributs props
et children
ici :
function createElement(node) { if (typeof node === ‘string’) { return document.createTextNode(node); } return document.createElement(node.type); }
Avec la méthode ci-dessus, je peux également créer deux types de nœuds, à savoir les nœuds de texte et les nœuds d'éléments Dom, qui sont des objets JS de type :
{ type: ‘…’, props: { … }, children: [ … ] }
Par conséquent, vous pouvez transmettre des nœuds de texte factices et des nœuds d'éléments factices dans functioncreateElement
- cela fonctionne.
Considérons maintenant les nœuds enfants – chacun d’eux est un nœud ou un élément de texte. Ils peuvent donc également être créés avec la fonction createElement(…). Oui, c'est comme la récursion, nous pouvons donc appeler createElement(…) pour les enfants de chaque élément, puis utiliser appendChild()
pour ajouter à notre élément :
function createElement(node) { if (typeof node === ‘string’) { return document.createTextNode(node); } const $el = document.createElement(node.type); node.children .map(createElement) .forEach($el.appendChild.bind($el)); return $el; }
Wow, ça a l'air bien. Mettons d’abord de côté l’attribut node props
. On se parle plus tard. Nous n'avons pas besoin qu'ils comprennent les concepts de base du DOM virtuel car ils ajoutent de la complexité.
Le code complet est le suivant :
/** @jsx h */ function h(type, props, ...children) { return { type, props, children }; } function createElement(node) { if (typeof node === 'string') { return document.createTextNode(node); } const $el = document.createElement(node.type); node.children .map(createElement) .forEach($el.appendChild.bind($el)); return $el; } const a = (
- item 1
- item 2
Comparez la différence entre deux arbres DOM virtuels
Nous pouvons maintenant convertir le DOM virtuel en un DOM réel, ce qui nécessite de comparer les deux arbres différences d'arbre DOM. Fondamentalement, nous avons besoin d'un algorithme pour comparer le nouvel arbre avec l'ancien arbre, ce qui nous permet de savoir ce qui a changé, puis de modifier le vrai DOM en conséquence.
Comment comparer les arbres DOM ? Les situations suivantes doivent être gérées :
- Pour ajouter un nouveau nœud, utilisez la méthode appendChild(…) pour ajouter un nœud
- Supprimez les anciens nœuds, utilisez la méthode removeChild(...) pour supprimer les anciens nœuds
- Remplacement des nœuds, utilisez la méthode replaceChild(…)
Si les nœuds sont les mêmes - vous devez comparer profondément les nœuds enfants
编写一个名为 updateElement(…) 的函数,它接受三个参数—— $parent
、newNode 和 oldNode,其中 $parent 是虚拟节点的一个实际 DOM 元素的父元素。现在来看看如何处理上面描述的所有情况。
添加新节点
function updateElement($parent, newNode, oldNode) { if (!oldNode) { $parent.appendChild( createElement(newNode) ); } }
移除老节点
这里遇到了一个问题——如果在新虚拟树的当前位置没有节点——我们应该从实际的 DOM 中删除它—— 这要如何做呢?
如果我们已知父元素(通过参数传递),我们就能调用 $parent.removeChild(…)
方法把变化映射到真实的 DOM 上。但前提是我们得知道我们的节点在父元素上的索引,我们才能通过 $parent.childNodes[index] 得到该节点的引用。
好的,让我们假设这个索引将被传递给 updateElement 函数(它确实会被传递——稍后将看到)。代码如下:
function updateElement($parent, newNode, oldNode, index = 0) { if (!oldNode) { $parent.appendChild( createElement(newNode) ); } else if (!newNode) { $parent.removeChild( $parent.childNodes[index] ); } }
节点的替换
首先,需要编写一个函数来比较两个节点(旧节点和新节点),并告诉节点是否真的发生了变化。还有需要考虑这个节点可以是元素或是文本节点:
function changed(node1, node2) { return typeof node1 !== typeof node2 || typeof node1 === ‘string’ && node1 !== node2 || node1.type !== node2.type }
现在,当前的节点有了 index 属性,就可以很简单的用新节点替换它:
function updateElement($parent, newNode, oldNode, index = 0) { if (!oldNode) { $parent.appendChild( createElement(newNode) ); } else if (!newNode) { $parent.removeChild( $parent.childNodes[index] ); } else if (changed(newNode, oldNode)) { $parent.replaceChild( createElement(newNode), $parent.childNodes[index] ); } }
比较子节点
最后,但并非最不重要的是——我们应该遍历这两个节点的每一个子节点并比较它们——实际上为每个节点调用updateElement(…)方法,同样需要用到递归。
- 当节点是 DOM 元素时我们才需要比较( 文本节点没有子节点 )
- 我们需要传递当前的节点的引用作为父节点
- 我们应该一个一个的比较所有的子节点,即使它是
undefined
也没有关系,我们的函数也会正确处理它。 - 最后是 index,它是子数组中子节点的 index
function updateElement($parent, newNode, oldNode, index = 0) { if (!oldNode) { $parent.appendChild( createElement(newNode) ); } else if (!newNode) { $parent.removeChild( $parent.childNodes[index] ); } else if (changed(newNode, oldNode)) { $parent.replaceChild( createElement(newNode), $parent.childNodes[index] ); } else if (newNode.type) { const newLength = newNode.children.length; const oldLength = oldNode.children.length; for (let i = 0; i <h2 id="完整的代码">完整的代码</h2><p><strong>Babel+JSX</strong><br>/<em>* @jsx h </em>/</p><pre class="brush:php;toolbar:false">function h(type, props, ...children) { return { type, props, children }; } function createElement(node) { if (typeof node === 'string') { return document.createTextNode(node); } const $el = document.createElement(node.type); node.children .map(createElement) .forEach($el.appendChild.bind($el)); return $el; } function changed(node1, node2) { return typeof node1 !== typeof node2 || typeof node1 === 'string' && node1 !== node2 || node1.type !== node2.type } function updateElement($parent, newNode, oldNode, index = 0) { if (!oldNode) { $parent.appendChild( createElement(newNode) ); } else if (!newNode) { $parent.removeChild( $parent.childNodes[index] ); } else if (changed(newNode, oldNode)) { $parent.replaceChild( createElement(newNode), $parent.childNodes[index] ); } else if (newNode.type) { const newLength = newNode.children.length; const oldLength = oldNode.children.length; for (let i = 0; i
- item 1
- hello!
HTML
<button>RELOAD</button> <p></p>
CSS
#root { border: 1px solid black; padding: 10px; margin: 30px 0 0 0; }
打开开发者工具,并观察当按下“Reload”按钮时应用的更改。
总结
现在我们已经编写了虚拟 DOM 实现及了解它的工作原理。作者希望,在阅读了本文之后,对理解虚拟 DOM 如何工作的基本概念以及在幕后如何进行响应有一定的了解。
然而,这里有一些东西没有突出显示(将在以后的文章中介绍它们):
- 设置元素属性(props)并进行 diffing/updating
- 处理事件——向元素中添加事件监听
- 让虚拟 DOM 与组件一起工作,比如React
- 获取对实际DOM节点的引用
- 使用带有库的虚拟 DOM,这些库可以直接改变真实的 DOM,比如 jQuery 及其插件
原文地址:https://medium.com/@deathmood/how-to-write-your-own-virtual-dom-ee74acc13060
作者:deathmood
为了保证的可读性,本文采用意译而非直译。
更多编程相关知识,请访问:编程入门!!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

PHP et Vue : une combinaison parfaite d'outils de développement front-end À l'ère actuelle de développement rapide d'Internet, le développement front-end est devenu de plus en plus important. Alors que les utilisateurs ont des exigences de plus en plus élevées en matière d’expérience des sites Web et des applications, les développeurs front-end doivent utiliser des outils plus efficaces et plus flexibles pour créer des interfaces réactives et interactives. En tant que deux technologies importantes dans le domaine du développement front-end, PHP et Vue.js peuvent être considérés comme une arme parfaite lorsqu'ils sont associés. Cet article explorera la combinaison de PHP et Vue, ainsi que des exemples de code détaillés pour aider les lecteurs à mieux comprendre et appliquer ces deux éléments.

Lors des entretiens de développement front-end, les questions courantes couvrent un large éventail de sujets, notamment les bases HTML/CSS, les bases JavaScript, les frameworks et les bibliothèques, l'expérience du projet, les algorithmes et les structures de données, l'optimisation des performances, les requêtes inter-domaines, l'ingénierie front-end, les modèles de conception et les nouvelles technologies et tendances. Les questions de l'intervieweur sont conçues pour évaluer les compétences techniques du candidat, son expérience en matière de projet et sa compréhension des tendances du secteur. Par conséquent, les candidats doivent être parfaitement préparés dans ces domaines pour démontrer leurs capacités et leur expertise.

Tutoriel JavaScript : Comment obtenir le code d'état HTTP, des exemples de code spécifiques sont requis Préface : Dans le développement Web, l'interaction des données avec le serveur est souvent impliquée. Lors de la communication avec le serveur, nous devons souvent obtenir le code d'état HTTP renvoyé pour déterminer si l'opération a réussi et effectuer le traitement correspondant en fonction de différents codes d'état. Cet article vous apprendra comment utiliser JavaScript pour obtenir des codes d'état HTTP et fournira quelques exemples de codes pratiques. Utilisation de XMLHttpRequest

Django est un framework d'application Web écrit en Python qui met l'accent sur un développement rapide et des méthodes propres. Bien que Django soit un framework Web, pour répondre à la question de savoir si Django est un front-end ou un back-end, vous devez avoir une compréhension approfondie des concepts de front-end et de back-end. Le front-end fait référence à l'interface avec laquelle les utilisateurs interagissent directement, et le back-end fait référence aux programmes côté serveur. Ils interagissent avec les données via le protocole HTTP. Lorsque le front-end et le back-end sont séparés, les programmes front-end et back-end peuvent être développés indépendamment pour mettre en œuvre respectivement la logique métier et les effets interactifs, ainsi que l'échange de données.

En tant que langage de programmation rapide et efficace, le langage Go est très populaire dans le domaine du développement back-end. Cependant, peu de gens associent le langage Go au développement front-end. En fait, l’utilisation du langage Go pour le développement front-end peut non seulement améliorer l’efficacité, mais également ouvrir de nouveaux horizons aux développeurs. Cet article explorera la possibilité d'utiliser le langage Go pour le développement front-end et fournira des exemples de code spécifiques pour aider les lecteurs à mieux comprendre ce domaine. Dans le développement front-end traditionnel, JavaScript, HTML et CSS sont souvent utilisés pour créer des interfaces utilisateur.

Combinaison de Golang et de la technologie front-end : pour explorer le rôle de Golang dans le domaine front-end, des exemples de code spécifiques sont nécessaires. Avec le développement rapide d'Internet et des applications mobiles, la technologie front-end est devenue de plus en plus importante. Dans ce domaine, Golang, en tant que puissant langage de programmation back-end, peut également jouer un rôle important. Cet article explorera comment Golang est combiné avec la technologie front-end et démontrera son potentiel dans le domaine front-end à travers des exemples de code spécifiques. Le rôle de Golang dans le domaine front-end est celui d'un outil efficace, concis et facile à apprendre.

Django : Un framework magique capable de gérer à la fois le développement front-end et back-end ! Django est un framework d'application Web efficace et évolutif. Il est capable de prendre en charge plusieurs modèles de développement Web, notamment MVC et MTV, et peut facilement développer des applications Web de haute qualité. Django prend non seulement en charge le développement back-end, mais peut également créer rapidement des interfaces frontales et obtenir un affichage de vue flexible via un langage de modèle. Django combine le développement front-end et le développement back-end dans une intégration transparente, afin que les développeurs n'aient pas à se spécialiser dans l'apprentissage.

Introduction à la méthode d'obtention du code d'état HTTP en JavaScript : Dans le développement front-end, nous devons souvent gérer l'interaction avec l'interface back-end, et le code d'état HTTP en est une partie très importante. Comprendre et obtenir les codes d'état HTTP nous aide à mieux gérer les données renvoyées par l'interface. Cet article explique comment utiliser JavaScript pour obtenir des codes d'état HTTP et fournit des exemples de code spécifiques. 1. Qu'est-ce que le code d'état HTTP ? Le code d'état HTTP signifie que lorsque le navigateur lance une requête au serveur, le service
