Beispiel für die Verwendung von JSX zum Erstellen einer Komponentenparserentwicklung

Beispiel für die Verwendung von JSX zum Erstellen einer Komponentenparserentwicklung

Hier bauen wir ein Komponentensystem von Grund auf. Zunächst wissen wir aus dem vorherigen Artikel „Grundlagen der Front-End-Komponentenbildung“, dass eine Komponente eine Umgebung ist, auf die über Markup und JavaScript zugegriffen werden kann.

Unser erster Schritt besteht also darin, eine Umgebung zu schaffen, in der wir Markup verwenden können. Hier lernen wir zwei Stile zum Erstellen von Markups kennen.

Das erste basiert auf JSX, dasselbe wie React, um unsere Komponenten zu stylen. Die zweite besteht darin, einen Stil auf Grundlage eines Parsers auf Basis einer Auszeichnungssprache zu erstellen, der Vue ähnelt.

Aufbau einer JSX-Umgebung

Im Allgemeinen wird JSX als Teil von React betrachtet. Tatsächlich definiert Facebook JSX als reine Spracherweiterung. Und dieses JSX kann auch von anderen Komponentensystemen verwendet werden.

Wir können es sogar verwenden, um schnell HTML-Tags zu erstellen.

Einrichten des Projekts

Beginnen wir also mit den Grundlagen. Zuerst müssen wir ein neues Projektverzeichnis erstellen:

mkdir jsx-Komponente

NPM initialisieren

Erstellen Sie diesen Projektordner in einem Verzeichnis Ihrer Wahl. Nachdem wir den Ordner erstellt haben, können wir das Verzeichnis aufrufen und npm initialisieren.

npm init

Nach der Ausführung des obigen Befehls werden einige Projektkonfigurationsoptionen angezeigt. Sie können diese bei Bedarf ausfüllen. Wir können jedoch auch einfach die Eingabetaste drücken und dann können die Studierenden, die es benötigen, package.json öffnen und es später selbst ändern.

Webpack installieren

Viele Studenten sollten von Wepack gehört haben, mit dem wir eine gewöhnliche JavaScript-Datei in eine Datei umwandeln können, in der verschiedene Import- und Anforderungsdateien zusammen verpackt werden können.

Also müssen wir webpack installieren. Natürlich können wir auch npx verwenden, um webpack direkt zu verwenden, oder wir können webpack-cli global installieren.

Daher verwenden wir hier die globale Installation von webpack-cli:

npm install -g webpack webpack-cli

Nachdem die Installation abgeschlossen ist, können wir die installierte Webpack-Version überprüfen, indem wir den folgenden Befehl eingeben. Wenn nach der Ausführung kein Fehler auftritt und eine Versionsnummer angezeigt wird, beweist dies, dass wir es erfolgreich installiert haben.

webpack --version

Installieren Sie Babel

Da JSX ein Babel-Plugin ist, müssen wir nacheinander Webpack, Babel-Loader, Babel und das Babel-Plugin installieren.

Es gibt hier noch einen weiteren Verwendungszweck für Babel. Es kann eine neue Version von JavaScript in eine alte Version von JavaScript kompilieren, sodass unser Code in mehreren älteren Browserversionen ausgeführt werden kann.

Um Babel zu installieren, müssen wir nur den folgenden Befehl ausführen.

npm install --save-dev webpack babel-loader

Was wir hier beachten müssen, ist, dass wir --save-dev hinzufügen müssen, damit wir Babel zu unseren Entwicklungsabhängigkeiten hinzufügen.

Nach der Ausführung sollten wir die im Bild oben angezeigte Meldung sehen.

Um zu überprüfen, ob wir es richtig installiert haben, können wir package.json in unserem Projektverzeichnis öffnen.

{
 "Name": "jsx-Komponente",
 "version": "1.0.0",
 "Beschreibung": "",
 "main": "index.js",
 "Skripte": {
 "test": "echo \"Fehler: kein Test angegeben\" && exit 1"
 },
 "Autor": "",
 "Lizenz": "ISC",
 "devAbhängigkeiten": {
 "babel-loader": "^8.1.0",
 "webpack": "^5.4.0"
 }
}

OK, wir können sehen, dass sich unter devDependencies tatsächlich die beiden Pakete befinden, die wir gerade installiert haben. Wenn Sie immer noch besorgt sind, können Sie package.json noch einmal überprüfen.

Konfigurieren von Webpack

An diesem Punkt müssen wir Webpack konfigurieren. Webpack konfigurieren Wir müssen eine Konfigurationsdatei webpack.config.js erstellen.

Erstellen Sie eine Datei webpack.config.js im Stammverzeichnis unseres Projekts.

Zunächst einmal ist die Webpack-Konfiguration ein Node.JS-Modul, daher müssen wir module.exports verwenden, um seine Einstellungen zu schreiben. Dies ist eine gängige Konfigurationsmethode für frühe Node.JS-Tools. Zur Konfiguration wird eine JavaScript-Datei verwendet, sodass der Konfiguration eine gewisse Logik hinzugefügt werden kann.

modul.exports = {}

Das Grundlegendste an Webpack ist, dass Sie einen Eintrag einrichten (seine Eintragsdatei festlegen) müssen. Hier haben wir einfach ein main.js eingerichtet.

modul.exporte = {
 Eintrag: "./main.js"
}

Zu diesem Zeitpunkt können wir zunächst eine main.js Datei in unserem Stammverzeichnis erstellen. Fügen wir zunächst eine einfache for Schleife hinzu.

// Inhalt der Datei main.js für (let i of [1, 2, 3]) {
 konsole.log(i);
}

Auf diese Weise wird die Grundkonfiguration von Webpack konfiguriert. Lassen Sie uns Webpack im Stammverzeichnis ausführen, um die Datei main.js zu packen und einen Blick darauf zu werfen. Zum Verpacken müssen Sie den folgenden Befehl ausführen:

Webpack 

Nachdem die Ausführung abgeschlossen ist, wird in der Befehlszeilenschnittstelle eine Eingabeaufforderung wie oben angezeigt.

Schüler, die auf Details achten, werden auf jeden Fall die Hand heben und fragen, Klassenkameraden! Es liegt ein Fehler in Ihrer Befehlszeile vor! Der gelbe Teil gibt uns zwar eine Warnung, aber das spielt keine Rolle, unsere nächste Konfiguration wird das Problem beheben.

Zu diesem Zeitpunkt werden wir feststellen, dass in unserem Stammverzeichnis ein neuer Ordner dist generiert wird. Dies ist der von Webpack standardmäßig generierte Ordner. Alle unsere gepackten JavaScripts und Ressourcen werden standardmäßig in diesem Ordner abgelegt.

Hier finden wir eine gepackte main.js Datei im Ordner dist . Dies ist main.js , die wir geschrieben haben und die von webpack gepackt wurde.

Dann öffnen wir es und sehen den JavaScript-Code, nachdem er von Babel kompiliert wurde. Wir werden feststellen, dass unseren wenigen Codezeilen viele Dinge hinzugefügt wurden. Tatsächlich müssen wir uns nicht darum kümmern, sie sind alle die „Miau-Power“ von Webpack.

Am Ende des Codes können Sie immer noch for Schleife sehen, die wir geschrieben haben. Sie wurde nur ein wenig geändert, aber ihre Funktion ist dieselbe.

Installieren Sie Babel-Loader

Als nächstes installieren wir babel-loader. Tatsächlich ist babel-loader nicht direkt von babel abhängig, daher müssen wir @babel/core und @babel/preset-env separat installieren. Um es zu installieren, müssen wir nur die folgende Befehlszeile ausführen:

npm install --save-dev @babel/core @babel/preset-env 

Das Endergebnis ist wie oben dargestellt und beweist, dass die Installation erfolgreich war. Jetzt müssen wir es in webpack.config.js konfigurieren, damit wir beim Verpacken den Babel-Loader verwenden können.

Fügen Sie nach entry von webpack.config.js , den wir oben konfiguriert haben, eine Option namens module hinzu.

Dann können wir dem Modul auch eine rules hinzufügen, die wir beim Erstellen verwenden. rules ist eine Konfiguration vom Array-Typ und jede Regel besteht hier aus einem test und einer use .

prüfen:

  • Der Wert von test ist ein regulärer Ausdruck, der zum Abgleichen der Dateien verwendet wird, für die wir diese Regel verwenden müssen. Hier müssen wir alle JavaScript-Dateien abgleichen, daher können wir /\.js/ verwenden.

Verwendung: Lader:

  • Fügen Sie einfach den Namen unseres babel-loader hinzu

Optionen:

Voreinstellungen:

  • Hier sind die Loader-Optionen, hier müssen wir @babel/preset-env hinzufügen

Schließlich sieht unsere Konfigurationsdatei folgendermaßen aus:

modul.exporte = {
 Eintrag: './main.js',
 Modul: {
 Regeln:
 {
 Test: /\.js$/,
 verwenden: {
 Lader: 'babel-loader',
 Optionen:
 Voreinstellungen: ['@babel/preset-env'],
 },
 },
 },
 ],
 },
};

Nachdem wir dies konfiguriert haben, können wir Babel ausführen, um es auszuprobieren. Wie zuvor müssen wir nur webpack auf der Befehlszeile ausführen.

Wenn unsere Konfigurationsdatei richtig geschrieben ist, sollten wir die in der Abbildung oben gezeigten Ergebnisse sehen.

Dann gehen wir in dist , öffnen unser kompiliertes main.js und schauen uns das Kompilierungsergebnis an, nachdem wir dieses Mal babel-loader verwendet haben.

Nach der Kompilierung werden wir feststellen, dass for of -Schleife in eine normale for Schleife kompiliert wurde. Dies beweist auch, dass unser Babel-Loader effektiv ist und unsere neue Version der JavaScript-Syntax korrekt in eine JavaScript-Syntax konvertiert, die mit älteren Browsern kompatibel ist.

An diesem Punkt haben wir die für JSX erforderliche Umgebung installiert und erstellt.

Moduskonfiguration

Schließlich müssen wir auch eine Umgebungskonfiguration in webpack.config.js hinzufügen. Dies ist jedoch optional, wir tun es jedoch zur Vereinfachung der täglichen Entwicklung.

Daher müssen wir in webpack.config.js einen mode hinzufügen, den wir für development verwenden. Diese Konfiguration zeigt an, dass wir uns im Entwicklermodus befinden.

Im Allgemeinen fügt die Webpack-Konfiguration, die wir in das Code-Repository schreiben, standardmäßig diesen mode: 'development' -Konfiguration. Wenn wir es tatsächlich veröffentlichen, ändern wir es in mode: 'production' .

modul.exporte = {
 Eintrag: './main.js',
 Modus: "Entwicklung",
 Modul: {
 Regeln:
 {
 Test: /\.js$/,
 verwenden: {
 Lader: 'babel-loader',
 Optionen:
 Voreinstellungen: ['@babel/preset-env'],
 },
 },
 },
 ],
 },
};

Nach der Änderung verwenden wir webpack zum Kompilieren und sehen, was der Unterschied in unserem main.js ist.

Offensichtlich haben wir festgestellt, dass der kompilierte Code nicht in einer Zeile komprimiert ist. Auf diese Weise können wir den von webpack generierten Code debuggen. Hier können wir feststellen, dass unser Code in main.js in einen String umgewandelt und in eine eval() Funktion eingefügt wird. Dann können wir es beim Debuggen als separate Datei verwenden und Breakpoint-Debugging durchführen.

JSX importieren

Alles ist bereit, bis auf den Ostwind. Und zum Schluss: Wie führen wir JSX ein? Sehen wir uns vor dem Importieren an, was passiert, wenn wir die JSX-Syntax in unserem main.js mit der aktuellen Konfiguration verwenden. Als Programmierer müssen wir immer ein bisschen abenteuerlustig sein!

Also fügen wir diesen Code in main.js ein:

var a = <div/>

Führen Sie dann mutig Webpack aus und sehen Sie!

Gute Arbeit! Tatsächlich wurde ein Fehler gemeldet. Der Fehler hier sagt uns, dass das „Kleiner-als-Zeichen“ nach = nicht verwendet werden kann, aber in der normalen JSX-Syntax sind dies tatsächlich die „spitzen Klammern“ des HTML-Tags. Da es keinen Kompilierungsprozess für die JSX-Syntax gibt, geht JavaScript standardmäßig davon aus, dass dies das „Kleiner-als-Zeichen“ ist.

Was müssen wir also tun, damit unser Webpack-Kompilierungsprozess die JSX-Syntax unterstützt? Hier müssen wir tatsächlich ein äußerst wichtiges Paket hinzufügen, und der Name dieses Pakets ist sehr lang und lautet @babel/plugin-transform-react-jsx . Führen Sie zur Installation den folgenden Befehl aus:

npm install --save-dev @babel/plugin-transform-react-jsx

Nach der Installation müssen wir es auch zur Webpack-Konfiguration hinzufügen. Wir müssen use in rules im module eine plugins -Konfiguration hinzufügen und dann ['@babel/plugin-transform-react-jsx'] hinzufügen.

Dann sieht unsere Webpack-Konfigurationsdatei schließlich so aus:

modul.exporte = {
 Eintrag: './main.js',
 Modus: "Entwicklung",
 Modul: {
 Regeln:
 {
 Test: /\.js$/,
 verwenden: {
 Lader: 'babel-loader',
 Optionen:
 Voreinstellungen: ['@babel/preset-env'],
 Plugins: ['@babel/plugin-transform-react-jsx'],
 },
 },
 },
 ],
 },
};

Lassen Sie uns nach der Konfiguration Webpack ausführen. Zu diesem Zeitpunkt stellten wir fest, dass kein Fehler mehr vorlag. Dies beweist, dass unser Code jetzt die Verwendung der JSX-Syntax unterstützt.

Schauen wir uns abschließend die endgültige Wirkung der Programmierung an.

Wir werden feststellen, dass <div/> das wir in eval hinzugefügt haben, in einen Funktionsaufruf von React.createElement("div", null) übersetzt wird.

Sehen wir uns also an, wie wir React.createElement implementieren sollten und ob wir es durch unseren eigenen Funktionsnamen ersetzen können.

Grundlegende JSX-Verwendung

Versuchen wir zunächst, JSX zu verstehen. JSX ist eigentlich nur eine Abkürzung in der Codesyntax. Am Ende des vorherigen Abschnitts haben wir gesehen, dass nach der Kompilierung der JSX-Syntax ein Aufruf von React.createElement erscheint.

JSX-Grundlagen

Daher ändern wir hier zuerst das JSX-Plugin im Webpack und geben ihm einen benutzerdefinierten Funktionsnamen zur Elementerstellung. Wir öffnen webpack.config.js und ändern es im Bereich Plugins.

modul.exporte = {
 Eintrag: './main.js',
 Modus: "Entwicklung",
 Modul: {
 Regeln:
 {
 Test: /\.js$/,
 verwenden: {
 Lader: 'babel-loader',
 Optionen:
 Voreinstellungen: ['@babel/preset-env'],
 Plugins: [
				[
					'@babel/plugin-transform-react-jsx',
					{ pragma: 'Element erstellen' }
				]
			],
 },
 },
 },
 ],
 },
};

Oben haben wir einfach den ursprünglichen Parameter ['@babel/plugin-transform-react-jsx'] [['@babel/plugin-transform-react-jsx', {pragma: 'createElement'}]] geändert. Durch Hinzufügen dieses pragma -Parameters können wir den Funktionsnamen des von uns erstellten Elements anpassen.

Mit dieser Änderung hat unser JSX nichts mehr mit dem React-Framework zu tun. Lassen Sie uns webpack ausführen und uns den endgültigen generierten Effekt ansehen. Wir werden feststellen, dass aus React.createElement createElement wird.

Als nächstes fügen wir eine HTML-Datei hinzu, um unser main.js auszuführen und auszuprobieren. Erstellen Sie zunächst eine main.html im Stammverzeichnis und geben Sie den folgenden Code ein:

<script src="./main.js"></script>

Anschließend führen wir diese HTML-Datei aus und öffnen sie im Browser.

Zu diesem Zeitpunkt gibt unsere Konsole einen Fehler aus und unser createElement ist nicht definiert. Tatsächlich haben wir diese Funktion nicht in main.js definiert und kann deshalb nicht gefunden werden.

Daher müssen wir selbst eine createElement -Funktion schreiben. Wir öffnen main.js direkt im Stammverzeichnis, löschen die vorherige for Schleife und fügen dann diesen Code hinzu:

Funktion erstelleElement() {
 zurückkehren;
}

sei a = <div />;

Hier geben wir einfach leer zurück und machen diese Funktion zuerst aufrufbar. Wir kompilieren einmal mit Webpack neu und aktualisieren dann unsere main.html-Seite. Zu diesem Zeitpunkt stellen wir fest, dass kein Fehler vorliegt und der Vorgang normal ausgeführt werden kann.

Implementieren der Funktion „createElement“

In unserem kompilierten Code können wir sehen, dass das JSX-Element beim Aufruf von createElement zwei Parameter übergibt. Das erste Argument ist div , das zweite ist null .

Warum ist der zweite Parameter hier null ? Tatsächlich wird der zweite Parameter verwendet, um die Attributliste zu übergeben. Wenn wir dem Div in main.js eine id="a" hinzufügen, sehen wir, welche Änderungen bei der endgültigen Kompilierung auftreten.

Wir werden feststellen, dass der zweite Parameter ein im Schlüssel-Wert-Modus gespeichertes JavaScript-Objekt wird. Wenn wir jetzt darüber nachdenken, ist JSX nicht so mysteriös. Es schreibt einfach das HTML, das wir normalerweise schreiben, durch Kompilierung in JavaScript-Objekte um. Wir können es uns als eine Art „[[Syntaxzucker]]“ vorstellen.

Da JSX jedoch die Struktur des Codes beeinflusst, wird es im Allgemeinen nicht als syntaktischer Zucker bezeichnet.

Als nächstes schreiben wir etwas komplexeres JSX. Wir werden dem ursprünglichen Div einige untergeordnete Elemente hinzufügen.

Funktion erstelleElement() {
 zurückkehren;
}

sei a = (
 <div id="ein">
 <span></span>
 <span></span>
 <span></span>
 </div>
);

Abschließend führen wir die folgende Webpack-Verpackung aus, um die Wirkung zu sehen.

In der Konsole können wir sehen, dass das endgültige kompilierte Ergebnis ein rekursiver Aufruf der Funktion createElement ist. Tatsächlich hat sich hier eine Baumstruktur gebildet.

Das übergeordnete Element ist das Div-Element der ersten Ebene und das untergeordnete Element ist der Parameter, der an die erste Funktion „createElement“ übergeben wird. Da unsere Spans keine Attribute haben, ist der zweite Parameter aller nachfolgenden createElements null .

Basierend auf dem hier angezeigten Kompilierungsergebnis können wir analysieren, wie die Parameter unserer Funktion createElement lauten sollten.

  • Der erste Parametertyp type ist der Typ dieses Tags
  • Das zweite attribute - alle Attribute und Werte im Tag
  • Die restlichen Parameter sind alle untergeordnete Eigenschaften ...children - Hier verwenden wir eine relativ neue Syntax in JavaScript ...children bedeutet, dass alle folgenden Parameter (unbestimmte Anzahl) in ein Array umgewandelt und der Variable children zugewiesen werden.

Dann kann unsere createElement -Funktion wie folgt geschrieben werden:

Funktion createElement(Typ, Attribute, ...Kinder) {
 zurückkehren;
}

Wir haben die Funktion, aber was kann diese Funktion? Tatsächlich kann diese Funktion für alles verwendet werden. Da sie wie eine DOM-API aussieht, können wir sie in ein Entity-DOM umwandeln, das nichts mit React zu tun hat.

Beispielsweise können wir in dieser Funktion das element dieses type zurückgeben. Hier fügen wir diesem Element alle übergebenen attributes hinzu und können diesem Element untergeordnete Elemente anhängen.

Zum Erstellen eines Elements können wir createElement(type) verwenden, zum Hinzufügen von Attributen können wir setAttribute() verwenden und zum Anhängen von untergeordneten Elementen können wir appendChild() verwenden.

Funktion createElement(Typ, Attribute, ...Kinder) {
 // Ein Element erstellen let element = document.createElement(type);
 //Attribute für (let-Attribut in Attributen) { anhängen
 element.setAttribute(attribute);
 }
 //Alle untergeordneten Elemente anhängen für (let child of children) {
 element.appendChild(Kind);
 }
 //Schließlich ist unser Element ein Knoten// also können wir direkt das Return-Element zurückgeben;
}

Hier implementieren wir die Logik der Funktion createElement . Schließlich müssen wir auch unseren DOM-Knoten auf der Seite mounten. So können wir es direkt am Körper montieren.

// Fügen Sie diesen Code am Ende von main.js hinzu let a = (
 <div id="ein">
 <span></span>
 <span></span>
 <span></span>
 </div>
);

Dokument.Body.AnhängenKind(a);

Hier ist auch zu beachten, dass in unserer main.html kein Body-Tag vorhanden ist. Ohne das Body-Element können wir es nicht am Body anbringen. Also müssen wir hier das Body-Element zu main.html hinzufügen.

<Körper></Körper>
<script src="dist/main.js"></script>

OK, jetzt können wir es mit Webpack verpacken und die Wirkung sehen.

Wunderbar! Wir haben den Knoten erfolgreich generiert und an den Körper angehängt. Wenn wir jedoch einen Textabschnitt zu unserem div hinzufügen, wird ein Textknoten an unsere Funktion createElement übergeben. Es ist unnötig zu erwähnen, dass unsere Funktion createElement mit ihrer aktuellen Logik keine Textknoten verarbeiten kann.

Als nächstes fügen wir die Logik zur Verarbeitung von Textknoten hinzu, aber vorher löschen wir das Span-Tag im Div und ersetzen es durch den Text „Hallo Welt“.

let a = <div id="a">Hallo Welt</div>;

Bevor wir die Logik des Textknotens hinzufügen, verpacken wir ihn mit webpack, um zu sehen, welche spezifischen Fehler gemeldet werden.

Zunächst können wir sehen, dass dort, wo createElement aufgerufen wird, unser Text als Zeichenfolge übergeben wird. Anschließend erhält dieser Parameter den untergeordneten Knoten. In unserer Logik verwenden wir appendChild , das den DOM-Knoten erhält. Unsere Textzeichenfolge ist offensichtlich kein Knoten, daher wird ein Fehler gemeldet.

Durch diese Debugging-Methode können wir sofort lokalisieren, wo wir Logik hinzufügen müssen, um diese Funktion zu implementieren. Diese Methode kann auch als Abkürzung betrachtet werden.

Kehren wir also zu main.js zurück. Bevor wir den untergeordneten Knoten anfügen, bestimmen wir den Typ des folgenden untergeordneten Knotens. Wenn sein Typ eine Zeichenfolge vom Typ „String“ ist, erstellen wir mit createTextNode() einen Textknoten und fügen ihn dann an das übergeordnete Element an. Auf diese Weise haben wir die Verarbeitung der Zeichenknoten abgeschlossen.

Funktion createElement(Typ, Attribute, ...Kinder) {
 // Ein Element erstellen let element = document.createElement(type);
 //Attribute für (Name in Attributen lassen) aufhängen {
 element.setAttribute(name, Attribute[name]);
 }
 //Alle untergeordneten Elemente anhängen für (let child of children) {
 wenn (Typ des untergeordneten Elements === 'Zeichenfolge') 
		Kind = Dokument.createTextNode(Kind);
 element.appendChild(Kind);
 }
 //Schließlich ist unser Element ein Knoten// also können wir direkt das Return-Element zurückgeben;
}

let a = <div id="a">Hallo Welt</div>;

Dokument.Body.AnhängenKind(a);

Nachdem wir diesen neuesten Webpack-Code zum Verpacken verwendet haben, können wir sehen, dass unser Text im Browser angezeigt wird.

An diesem Punkt ist createElement bereits eine nützliche Sache und wir können es verwenden, um einige DOM-Operationen durchzuführen. Es kann sogar den sich wiederholenden und langwierigen Vorgang des eigenen Schreibens von document.createElement vollständig ersetzen.

Hier können wir Folgendes überprüfen. Wir fügen unsere vorherigen drei Spans wieder in das Div ein und fügen jedem Span Text hinzu. 11

sei a = (
 <div id="ein">
 hallo Welt:
 <span>ein</span>
 <span>b</span>
 <span>c</span>
 </div>
);

Nachdem wir das Webpack erneut gepackt haben, können wir sehen, dass dieser DOM-Vorgang tatsächlich abgeschlossen werden kann.

Der aktuelle Code kann bereits bestimmte grundlegende Komponentenfunktionen erreichen.

Implementieren von benutzerdefinierten Tags

Früher haben wir einige Tags verwendet, die mit HTML geliefert wurden. Was passiert, wenn wir jetzt das d in div in ein großes D ändern?

sei a = (
 <Div id="a">
 hallo Welt:
 <span>ein</span>
 <span>b</span>
 <span>c</span>
 </Div>
); 

Wie erwartet wird ein Fehler gemeldet. Aber wir haben den Schlüssel zur Wurzel des Problems gefunden. Hier haben wir festgestellt, dass sich beim Ändern von div in Div das an unser createElement übergebene div von der Zeichenfolge „div“ in eine Div Klasse geändert hat.

Natürlich ist die Div-Klasse in unserem JavaScript nicht definiert, daher wird ein Fehler gemeldet, der darauf hinweist, dass Div nicht definiert ist. Wenn wir wissen, wo das Problem liegt, können wir es lösen. Zuerst müssen wir das undefinierte Problem lösen, also erstellen wir zuerst eine Div-Klasse.

//Füge die Klasse Div {} nach der Funktion createElment hinzu

Dann müssen wir in createElement eine Typbeurteilung vornehmen. Wenn der Typ, auf den wir stoßen, ein Zeichentyp ist, behandeln wir ihn auf die ursprüngliche Weise. Wenn wir auf eine andere Situation stoßen, instanziieren wir den übergebenen type .

Funktion createElement(Typ, Attribute, ...Kinder) {
 //Element erstellen let element;
 wenn (Typ von Typ === 'Zeichenfolge') {
 Element = Dokument.Elementerstellen(Typ);
 } anders {
 Element = neuer Typ();
 }

 //Attribute für (Name in Attributen lassen) aufhängen {
 element.setAttribute(name, Attribute[name]);
 }
 //Alle untergeordneten Elemente anhängen für (let child of children) {
 wenn (Typ des untergeordneten Elements === 'Zeichenfolge') untergeordnetes Element = Dokument.createTextNode(untergeordnetes Element);
 element.appendChild(Kind);
 }
 //Schließlich ist unser Element ein Knoten// also können wir direkt das Return-Element zurückgeben;
}

Hier haben wir eine weitere Frage: Gibt es eine Möglichkeit, benutzerdefinierte Tags wie unsere normalen HTML-Tags funktionieren zu lassen? In der neuesten Version des DOM-Standards gibt es hierfür eine Möglichkeit. Wir müssen lediglich den Namen und den Typ unseres benutzerdefinierten Tags registrieren.

In unserer aktuellen, sichereren Browserversion wird dies jedoch nicht empfohlen. Daher wird bei Verwendung unseres benutzerdefinierten Elements empfohlen, dass wir selbst eine Schnittstelle schreiben.

Zuerst müssen wir eine Tag-Klasse erstellen, die es ermöglicht, jedes Tag in unserem DOM-Baum einzubinden, wie die Elemente unserer vorherigen gewöhnlichen HTML-Tags.

Es wird die folgenden Methoden enthalten:

  • mountTo() —— Erstellen Sie einen Elementknoten für die spätere Einbindung in parent Knoten
  • setAttribute() - alle Attribute an ein Element anhängen
  • appendChild() - hängt alle Kindelemente an ein Element an

Lassen Sie uns zunächst einfach die Methode mountTo in unserer Div Klasse implementieren. Hier müssen wir auch die Methoden setAttribute und appendChild hinzufügen, da es in unserem createElement eine Logik zum Mounten von Attribut-Unterelementen gibt. Wenn diese beiden Methoden nicht verfügbar sind, wird ein Fehler gemeldet. Aber dieses Mal implementieren wir die Logik dieser beiden Methoden nicht und lassen den Methodeninhalt einfach leer.

Klasse Div {
 setAttribute() {}
 anhängenKind() {}
 mountTo(übergeordnet) {
 dies.root = Dokument.createElement('div');
 übergeordnetes Element.AnhängenKind(diese.Wurzel);
 }
}

Dies ist eigentlich ganz einfach. Erstellen Sie zunächst einen Div-Elementknoten für root in der Klasse und hängen Sie diesen Knoten dann an das übergeordnete Element dieses Elements an. Dieses parent wird als Parameter übergeben.

Dann können wir unseren ursprünglichen body.appendChild-Code ändern, um die mountTo Methode zum Mounten unserer benutzerdefinierten Elementklasse zu verwenden.

// Dokument.Body.AppendChild(a);
a.mountTo(Dokument.Textkörper);

Mit dem aktuellen Code verpacken wir ihn mit webpack, um die Wirkung zu sehen:

Wir können sehen, dass unser benutzerdefiniertes Div-Element korrekt am Körper montiert ist. Aber die Span-Tags im Div sind nicht gemountet. Wenn es wie ein normales Div funktionieren soll, müssen wir unsere setAttribute und appendChild -Logik implementieren.

Versuchen wir als Nächstes, die verbleibende Implementierungslogik zu vervollständigen. Bevor wir mit dem Schreiben von setAttribute und appendChild beginnen, müssen wir unserer Div-Klasse einen constructor hinzufügen. Hier können wir das Element erstellen und es per Proxy an root senden.

Konstruktor() {
 dies.root = Dokument.createElement('div');
}

Dann ist die setAttribute -Methode eigentlich sehr einfach. Verwenden Sie einfach this.root und rufen Sie setAttribute in der DOM-API auf. Dasselbe gilt für appendChild . Schließlich sieht unser Code wie folgt aus:

Klasse Div {
 // Konstruktor // DOM-Knoten erstellen konstruktor() {
 dies.root = Dokument.createElement('div');
 }
 // Die Attribute des Elements mounten setAttribute(name, attribute) {
 this.root.setAttribute(Name, Attribut);
 }
 // Element untergeordnetes Element mounten appendChild(child) {
 dies.root.appendChild(Kind);
 }
 // Das aktuelle Element mounten mountTo(parent) {
 übergeordnetes Element.AnhängenKind(diese.Wurzel);
 }
}

Verpacken wir es mit Webpack, um die Wirkung zu sehen:

Wir können sehen, dass sowohl Div als auch Span erfolgreich am Body montiert sind. Es beweist auch, dass unser selbst erstelltes Div normal funktionieren kann.

Hier gibt es noch ein weiteres Problem, da wir schließlich a.mountTo() aufgerufen haben. Wenn unsere Variable a kein benutzerdefiniertes Element, sondern unser normales HTML-Element ist, verfügt sie zu diesem Zeitpunkt nicht über die Methode mountTo .

Deshalb müssen wir hier auch gewöhnlichen Elementen eine Wrapper-Klasse hinzufügen, damit sie das Standardformat unserer Elementklasse beibehalten können. Es wird auch als Standardschnittstelle bezeichnet.

Schreiben wir zunächst eine ElementWrapper -Klasse. Der Inhalt dieser Klasse ist im Grunde derselbe wie bei unserem Div. Es gibt nur zwei Unterschiede

  1. Beim Erstellen eines DOM-Knotens können wir den aktuellen type an unseren Konstruktor übergeben und diesen Typ zum Erstellen unseres DOM-Knotens verwenden.
  2. appendChild kann this.root.appendChild nicht direkt verwenden, da alle normalen Tags in unsere benutzerdefinierte Klasse geändert wurden. Daher muss die Logik von appendChild child.mountTo(this.root) geändert werden.
Klasse ElementWrapper {
 // Konstruktor // DOM-Knoten erstellen Konstruktor (Typ) {
 this.root = document.createElement(Typ);
 }
 // Die Attribute des Elements mounten setAttribute(name, attribute) {
 this.root.setAttribute(Name, Attribut);
 }
 // Element untergeordnetes Element mounten appendChild(child) {
 Kind.mountTo(diese.Wurzel);
 }
 // Das aktuelle Element mounten mountTo(parent) {
 übergeordnetes Element.AnhängenKind(diese.Wurzel);
 }
}

Klasse Div {
 // Konstruktor // DOM-Knoten erstellen konstruktor() {
 dies.root = Dokument.createElement('div');
 }
 // Die Attribute des Elements mounten setAttribute(name, attribute) {
 this.root.setAttribute(Name, Attribut);
 }
 // Element untergeordnetes Element mounten appendChild(child) {
 Kind.mountTo(diese.Wurzel);
 }
 // Das aktuelle Element mounten mountTo(parent) {
 übergeordnetes Element.anhängenKind(diese.Wurzel);
 }
}

Wir haben hier immer noch ein Problem: Wenn wir auf einen Textknoten stoßen, wird dieser nicht in unsere benutzerdefinierte Klasse konvertiert. Deshalb müssen wir auch einen für den Textknoten schreiben, genannt TextWrapper .

Klasse TextWrapper {
 // Konstruktor // DOM-Knoten erstellen Konstruktor (Inhalt) {
 this.root = document.createTextNode(Inhalt);
 }
 // Die Attribute des Elements mounten setAttribute(name, attribute) {
 this.root.setAttribute(Name, Attribut);
 }
 // Element untergeordnetes Element mounten appendChild(child) {
 Kind.mountTo(diese.Wurzel);
 }
 // Das aktuelle Element mounten mountTo(parent) {
 übergeordnetes Element.anhängenKind(diese.Wurzel);
 }
}

Mit diesen Elementklassenschnittstellen können wir die Logik in unserem createElement neu schreiben. Ersetzen Sie einfach unsere ursprünglichen document.createElement und document.createTextNode durch die Instanziierung von new ElementWrapper(type) und new TextWrapper(content) .

Funktion createElement(Typ, Attribute, ...Kinder) {
 //Element erstellen let element;
 wenn (Typ von Typ === 'Zeichenfolge') {
 Element = neuer ElementWrapper(Typ);
 } anders {
 Element = neuer Typ();
 }

 //Attribute für (Name in Attributen lassen) aufhängen {
 element.setAttribute(name, Attribute[name]);
 }
 //Alle untergeordneten Elemente anhängen für (let child of children) {
 wenn (Typ des untergeordneten Elements === 'Zeichenfolge') 
		Kind = neuer TextWrapper(Kind);
 element.appendChild(Kind);
 }
 //Schließlich ist unser Element ein Knoten// also können wir direkt das Return-Element zurückgeben;
}

Dann verpacken wir es mit Webpack und sehen nach.

Es gibt keine Überraschungen, dass unser gesamtes Element normal am Körper montiert ist. Und wenn wir unser Div wieder in div ändern, funktioniert es auch ordnungsgemäß.

Natürlich schreiben wir grundsätzlich kein bedeutungsloses Div-Element. Hier schreiben wir den Namen unserer Komponente, beispielsweise Carousel , eine Komponente für ein Karussell.

Vollständiger Code – bitte geben Sie mir ein ⭐️, wenn Ihnen das hilft, danke!


Hier betreuen wir uns gegenseitig, ermutigen uns gegenseitig und arbeiten gemeinsam hart daran, den Weg des Lernens im Leben einzuschlagen und zuzulassen, dass das Lernen unser Leben verändert!

Der Weg zum Lernen ist langweilig und einsam, aber ich hoffe, dass dies uns mehr Kameradschaft und Ermutigung bringen kann. Lasst uns gemeinsam anfeuern! (๑ •̀ㅂ•́)و


Dies ist das Ende dieses Artikels über die Verwendung von JSX zum Erstellen eines Komponentenparsers (Parser)-Entwicklungsbeispiels. Weitere relevante Inhalte zum JSX-Komponentenparser finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder durchsuchen Sie die folgenden verwandten Artikel weiter. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Detaillierte Erläuterung inkompatibler Änderungen an Rendering-Funktionen in Vue3
  • Detaillierte Erläuterung der Verwendung der Vue-Rendering-Funktion Render
  • Detaillierte Erläuterung der Vue-Rendering-Funktion
  • So verwenden Sie die JSX-Syntax richtig in Vue
  • Probleme und Lösungen bei der Verwendung der jsx-Syntax in React-vscode
  • So verwenden Sie JSX zum Implementieren von Karussellkomponenten (Front-End-Komponentenbildung)
  • Spezifische Verwendung der JSX-Syntax von Vue-Komponenten
  • Vue jsx-Nutzungshandbuch und Verwendung der jsx-Syntax in vue.js
  • Detaillierte Erklärung, wie Vue die JSX-Syntax unterstützt
  • Rendering-Funktion und JSX-Details

<<:  Tutorial zur Installation von MySQL auf Alibaba Cloud Centos 7.5

>>:  Zusammenfassung einiger meiner häufig verwendeten Linux-Befehle

Artikel empfehlen

Detaillierte Erklärung der Beziehung zwischen Linux- und GNU-Systemen

Inhaltsverzeichnis Was ist das Linux-System, das ...

Grundlegende Syntax des MySQL-Index

Ein Index ist eine sortierte Datenstruktur! Die F...

Detaillierte Erläuterung des grundlegenden Falls des React.js-Frameworks Redux

react.js Rahmen Redux https://github.com/reactjs/...

Detaillierte Erklärung der scp- und sftp-Befehle unter Linux

Inhaltsverzeichnis Vorwort 1. SCP-Nutzung 2. Verw...

So verwenden Sie Docker+DevPi zum Erstellen einer lokalen PyPi-Quelle

Vor einiger Zeit musste ich für die Entwicklung h...

Eine kurze Diskussion über die Verwendung der Web Storage API

Inhaltsverzeichnis 1. Lokale Speichertechnologie ...

Beispielcode zum Vergleich verschiedener Syntaxformate von vue3

Die Standardvorlagenmethode ähnelt vue2 und verwe...

Detaillierte Erläuterung der Verwendung der MySQL-Verkettungsfunktion CONCAT

In den vorherigen Artikeln wurden die Ersetzungsf...

Über MySQL innodb_autoinc_lock_mode

Der Parameter innodb_autoinc_lock_mode steuert da...

Detaillierte Erklärung der JS-Ereignisdelegation

1. Jede Funktion ist ein Objekt und belegt Speich...