Letzten Monat schrieb Chris Coyier einen Beitrag, in dem er die Frage untersuchte: „Wann braucht ein Projekt React?“ Mit anderen Worten, wann überwiegen die Vorteile der Verwendung von React (als Stellvertreter für datengesteuerte Web-Frameworks im Allgemeinen) gegenüber serverseitigen Vorlagen und jQuery, die zusätzliche Komplexität bei der Einrichtung der erforderlichen Werkzeuge, des Build-Prozesses, der Abhängigkeiten usw. aufweisen? Eine Woche später schrieb Sacha Greif einen Gegenbeitrag, in dem er argumentierte, warum man solche Frameworks immer für jede Art von Webprojekt verwenden sollte. Seine Argumente umfassten Zukunftssicherheit, vereinfachten Workflow von Projekt zu Projekt (eine einzige Architektur; keine Notwendigkeit, mehrere Arten von Projektstrukturen zu verfolgen) und verbesserte Benutzererfahrung durch clientseitiges Neu-Rendering, auch wenn sich der Inhalt nicht sehr oft ändert.
In diesem Beitragspaar vertiefe ich mich in einen Mittelweg: Das Schreiben von UI's im reaktiven Stil in reinem JavaScript – keine Frameworks, keine Präprozessoren.
Artikelserie
- Rein funktionaler Stil (Du bist hier!)
- Klassenbasierte Komponenten
Es gibt zwei sehr unterschiedliche Möglichkeiten, React-Komponenten zu schreiben.
- Man kann sie als Klassen schreiben. Zustandsbehaftete Objekte mit Lifecycle-Hooks und internen Daten.
- Oder man kann sie als Funktionen schreiben. Nur ein Stück HTML, das basierend auf übergebenen Parametern konstruiert und aktualisiert wird.
Ersteres ist oft nützlicher für große, komplexe Anwendungen mit vielen beweglichen Teilen, während letzteres eine elegantere Möglichkeit ist, Informationen anzuzeigen, wenn man nicht viel dynamischen Zustand hat. Wenn Sie jemals eine Vorlagen-Engine wie Handlebars oder Swig verwendet haben, ähnelt deren Syntax dem funktionsbasierten React-Code.
In diesem Beitragspaar ist unser Zielanwendungsfall Websites, die ansonsten statisch sein könnten, aber von JavaScript-basiertem Rendering profitieren würden, wenn nicht der Overhead für die Einrichtung eines Frameworks wie React wäre. Blogs, Foren usw. Daher konzentriert sich dieser erste Beitrag auf den funktionalen Ansatz zum Schreiben einer komponentenbasierte UI, da dieser für diesen Szenariotyp praktischer ist. Der zweite Beitrag wird eher ein Experiment sein; ich werde die Grenzen ausreizen, wie weit wir Dinge ohne Framework bringen können, und versuchen, das klassenbasierte Komponentenmuster von React mit nur Vanilla JavaScript so genau wie möglich zu replizieren, wahrscheinlich auf Kosten einiger Praktikabilität.
Über funktionale Programmierung
Funktionale Programmierung hat in den letzten Jahren enorm an Popularität gewonnen, hauptsächlich angetrieben durch Clojure, Python und React. Eine vollständige Erklärung der funktionalen Programmierung liegt außerhalb des Rahmens dieses Beitrags, aber der Teil, der für uns jetzt relevant ist, ist das Konzept von Werten, die Funktionen anderer Werte sind.
Nehmen wir an, Ihr Code muss das Konzept eines Rechtecks darstellen. Ein Rechteck hat Breite und Höhe, aber auch Fläche, Umfang und andere Attribute. Zuerst könnte man denken, ein Rechteck mit dem folgenden Objekt darzustellen
var rectangle = {
width: 2,
height: 3,
area: 6,
perimeter: 10
};
Aber es würde sich schnell herausstellen, dass es ein Problem gibt. Was passiert, wenn sich die Breite ändert? Jetzt müssen wir auch Fläche und Umfang ändern, sonst wären sie falsch. Es ist möglich, widersprüchliche Werte zu haben, bei denen man nicht einfach einen ändern kann, ohne die Möglichkeit zu haben, etwas anderes zu aktualisieren. Dies wird als mehrere Wahrheitsquellen bezeichnet.
Im Rechteckbeispiel ist die Lösung im Stil der funktionalen Programmierung, area und perimeter in Funktionen eines Rechtecks zu verwandeln
var rectangle = {
width: 2,
height: 3
};
function area(rect) {
return rect.width * rect.height;
}
function perimeter(rect) {
return rect.width * 2 + rect.height * 2;
}
area(rectangle); // = 6
perimeter(rectangle); // = 10
Auf diese Weise müssen wir nichts anderes manuell ändern, wenn sich width oder height ändern. Die area und perimeter sind einfach korrekt. Dies wird als einzige Wahrheitsquelle bezeichnet.
Diese Idee ist wirkungsvoll, wenn Sie das Rechteck durch die Daten ersetzen, die Ihre Anwendung möglicherweise hat, und die Fläche und den Umfang durch HTML. Wenn Sie Ihr HTML zu einer Funktion Ihrer Daten machen können, dann müssen Sie sich nur noch um die Änderung der Daten kümmern – nicht um das DOM –, und die Art und Weise, wie es auf der Seite gerendert wird, wird implizit sein.
UI-Komponenten als Funktionen
Wir möchten unser HTML zu einer Funktion unserer Daten machen. Nehmen wir das Beispiel eines Blogbeitrags
var blogPost = {
author: 'Brandon Smith',
title: 'A CSS Trick',
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
};
function PostPage(postData) {
return '<div class="page">' +
'<div class="header">' +
'Home' +
'About' +
'Contact' +
'</div>' +
'<div class="post">' +
'<h1>' + postData.title + '</h1>' +
'<h3>By ' + postData.author + '</h3>' +
'<p>' + postData.body + '</p>' +
'</div>' +
'</div>';
}
document.querySelector('body').innerHTML = PostPage(blogPost);
Okay. Wir haben eine Funktion eines Beitrags-Objekts erstellt, die einen HTML-String zurückgibt, der unseren Blogbeitrag rendert. Es ist jedoch noch nicht wirklich „komponentisiert“. Es ist alles eine große Sache. Was ist, wenn wir auch alle unsere Blogbeiträge nacheinander auf der Homepage rendern wollen? Was ist, wenn wir diese Kopfzeile auf verschiedenen Seiten wiederverwenden wollen? Glücklicherweise ist es sehr einfach, Funktionen aus anderen Funktionen aufzubauen. Dies wird als Komponieren von Funktionen bezeichnet
var blogPost = {
author: 'Brandon Smith',
title: 'A CSS Trick',
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
};
function Header() {
return '<div class="header">' +
'Home' +
'About' +
'Contact' +
'</div>';
}
function BlogPost(postData) {
return '<div class="post">' +
'<h1>' + postData.title + '</h1>' +
'<h3>By ' + postData.author + '</h3>' +
'<p>' + postData.body + '</p>' +
'</div>';
}
function PostPage(postData) {
return '<div class="page">' +
Header() +
BlogPost(postData) +
'</div>';
}
function HomePage() {
return '<div class="page">' +
Header() +
'<h1>Welcome to my blog!</h1>' +
'<p>It\'s about lorem ipsum dolor sit amet, consectetur ad...</p>' +
'</div>';
}
document.querySelector('body').innerHTML = PostPage(blogPost);
Das ist viel schöner. Wir mussten die Kopfzeile nicht für die Homepage duplizieren; wir haben eine einzige Wahrheitsquelle für diesen HTML-Code. Wenn wir einen Beitrag in einem anderen Kontext anzeigen möchten, könnten wir dies einfach tun.
Schönere Syntax mit Template-Literalen
Okay, aber all diese Pluszeichen sind schrecklich. Sie sind mühsam zu tippen und machen es schwerer zu lesen, was passiert. Es muss einen besseren Weg geben, oder? Nun, die Leute vom W3C sind Ihnen weit voraus. Sie haben Template-Literale erfunden – die, obwohl sie noch relativ neu sind, ziemlich gute Browserunterstützung zu diesem Zeitpunkt haben. Wickeln Sie Ihre Zeichenkette einfach in Backticks anstelle von Anführungszeichen, und sie erhält ein paar zusätzliche Superkräfte.
Die erste Superkraft ist die Fähigkeit, sich über mehrere Zeilen zu erstrecken. Unser BlogPost-Komponente kann also werden
// ...
function BlogPost(postData) {
return `<div class="post">
<h1>` + postData.title + `</h1>
<h3>By ` + postData.author + `</h3>
<p>` + postData.body + `</p>
</div>`;
}
// ...
Das ist schön. Aber die andere Kraft ist noch schöner: Variablensubstitution. Variablen (oder beliebige JavaScript-Ausdrücke, einschließlich Funktionsaufrufe!) können direkt in die Zeichenkette eingefügt werden, wenn sie in ${ } eingeschlossen sind.
// ...
function BlogPost(postData) {
return `<div class="post">
<h1>${postData.title}</h1>
<h3>By ${postData.author}</h3>
<p>${postData.body}</p>
</div>`;
}
// ...
Viel besser. Es sieht jetzt fast aus wie JSX. Sehen wir uns unser vollständiges Beispiel noch einmal an, mit Template-Literalen
var blogPost = {
author: 'Brandon Smith',
title: 'A CSS Trick',
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
};
function Header() {
return `<div class="header">
Home
About
Contact
</div>`;
}
function BlogPost(postData) {
return `<div class="post">
<h1>${postData.title}</h1>
<h3>By ${postData.author}</h3>
<p>${postData.body}</p>
</div>`;
}
function PostPage(postData) {
return `<div class="page">
${Header()}
${BlogPost(postData)}
</div>`;
}
function HomePage() {
return `<div class="page">
${Header()}
<h1>Welcome to my blog!</h1>
<p>It's about lorem ipsum dolor sit amet, consectetur ad...</p>
</div>`;
}
document.querySelector('body').innerHTML = PostPage(blogPost);
Mehr als nur Lücken füllen
Wir können also Variablen und sogar andere Komponenten über Funktionen einfüllen, aber manchmal ist eine komplexere Rendering-Logik notwendig. Manchmal müssen wir über Daten iterieren oder auf eine Bedingung reagieren. Lassen Sie uns einige JavaScript-Sprachfeatures durchgehen, die es einfacher machen, komplexeres Rendering in einem funktionalen Stil durchzuführen.
Der ternäre Operator
Wir beginnen mit der einfachsten Logik: if-else. Natürlich könnten wir, da unsere UI-Komponenten nur Funktionen sind, ein tatsächliches if-else verwenden, wenn wir wollten. Sehen wir uns an, wie das aussehen würde
var blogPost = {
isSponsored: true,
author: 'Brandon Smith',
title: 'A CSS Trick',
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
};
function BlogPost(postData) {
var badgeElement;
if(postData.isSponsored) {
badgeElement = `<img src="badge.png">`;
} else {
badgeElement = '';
}
return `<div class="post">
<h1>${postData.title} ${badgeElement}</h1>
<h3>By ${postData.author}</h3>
<p>${postData.body}</p>
</div>`;
}
Das ist… nicht ideal. Es fügt eine ganze Menge Zeilen für etwas hinzu, das nicht so kompliziert ist, und es trennt einen Teil unseres Rendering-Codes von seinem Platz im Rest des HTML. Das liegt daran, dass eine klassische if-else-Anweisung entscheidet, welche Codezeilen ausgeführt werden, anstatt welchen Wert ausgewertet werden soll. Dies ist eine wichtige Unterscheidung zu verstehen. Sie können nur einen Ausdruck in ein Template-Literal einfügen, nicht eine Reihe von Anweisungen.
Der ternäre Operator ist wie ein if-else, aber für einen Ausdruck statt für eine Reihe von Anweisungen
var wantsToGo = true;
var response = wantsToGo ? 'Yes' : 'No'; // response = 'Yes'
wantsToGo = false;
response = wantsToGo ? 'Yes' : 'No'; // response = 'No'
Er hat die Form [Bedingung] ? [WertWennWahr] : [WertWennFalsch]. Der Blogbeitragsbeispiel oben wird also zu
var blogPost = {
isSponsored: true,
author: 'Brandon Smith',
title: 'A CSS Trick',
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
};
function BlogPost(postData) {
return `<div class="post">
<h1>
${postData.title} ${postData.isSponsored ? '<img src="badge.png">' : ''}
</h1>
<h3>By ${postData.author}</h3>
<p>${postData.body}</p>
</div>`;
}
Viel besser.
Array.map()
Nun zu den Schleifen. Wann immer wir ein Array von Daten haben, das wir rendern wollen, müssen wir über diese Werte iterieren, um das entsprechende HTML zu generieren. Aber wenn wir eine for-Schleife verwenden würden, würden wir auf das gleiche Problem stoßen wie bei der if-else-Anweisung oben. Eine for-Schleife evaluiert keinen Wert, sie führt eine Reihe von Anweisungen auf eine bestimmte Weise aus. Glücklicherweise hat ES6 einige sehr hilfreiche Methoden zum Array-Typ hinzugefügt, die diesem spezifischen Bedarf dienen.
Array.map() ist eine Array-Methode, die ein einzelnes Argument nimmt, nämlich eine Callback-Funktion. Sie durchläuft das Array, auf dem sie aufgerufen wird (ähnlich wie Array.forEach()), und ruft den bereitgestellten Callback einmal für jedes Element auf, wobei das Array-Element als Argument übergeben wird. Der Unterschied zu Array.forEach() besteht darin, dass der Callback einen Wert zurückgeben soll – vermutlich einen, der auf dem entsprechenden Element im Array basiert –, und der gesamte Ausdruck gibt das neue Array aller von der Callback-Funktion zurückgegebenen Elemente zurück. Zum Beispiel
var myArray = [ 'zero', 'one', 'two', 'three' ];
// evaluates to [ 'ZERO', 'ONE', 'TWO', 'THREE' ]
var capitalizedArray = myArray.map(function(item) {
return item.toUpperCase();
});
Sie können vielleicht erraten, warum das so nützlich für das ist, was wir tun. Früher haben wir das Konzept eines Wertes, der eine Funktion eines anderen Wertes ist, etabliert. Array.map() ermöglicht es uns, ein ganzes Array zu erhalten, bei dem jedes Element eine Funktion des entsprechenden Elements in einem anderen Array ist. Nehmen wir an, wir haben ein Array von Blogbeiträgen, die wir anzeigen möchten
function BlogPost(postData) {
return `<div class="post">
<h1>${postData.title}</h1>
<h3>By ${postData.author}</h3>
<p>${postData.body}</p>
</div>`;
}
function BlogPostList(posts) {
return `<div class="blog-post-list">
${posts.map(BlogPost).join('')}
</div>`
}
var allPosts = [
{
author: 'Brandon Smith',
title: 'A CSS Trick',
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
},
{
author: 'Chris Coyier',
title: 'Another CSS Trick',
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
},
{
author: 'Bob Saget',
title: 'A Home Video',
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
}
]
document.querySelector('body').innerHTML = BlogPostList(allPosts);
Jedes Objekt, das die Informationen für einen einzelnen Blogbeitrag enthält, wird nacheinander an die BlogPost-Funktion übergeben, und die zurückgegebenen HTML-Strings werden in ein neues Array eingefügt. Wir rufen dann einfach join() auf diesem neuen Array auf, um das Array von Strings zu einem einzigen String zu kombinieren (getrennt durch einen leeren String), und fertig. Keine for-Schleifen, nur eine Liste von Objekten, die in eine Liste von HTML-Elementen umgewandelt werden.
Neu-Rendering
Wir können nun implizit HTML für gegebene Daten generieren, auf eine Weise, die wiederverwendbar und komponierbar ist, alles im Browser. Aber wie aktualisieren wir, wenn sich die Daten ändern? Woher wissen wir überhaupt, wann wir ein Update auslösen sollen? Dieses Thema ist heute eines der komplexesten und am heißesten diskutierten in der JavaScript-Framework-Community. Das effiziente Aktualisieren großer Mengen von DOM-Änderungen ist ein erstaunlich schwieriges Problem, an dem Ingenieure bei Facebook und Google jahrelang gearbeitet haben.
Glücklicherweise ist unsere sprichwörtliche Website nur ein Blog. Der Inhalt ändert sich so ziemlich nur, wenn wir uns einen anderen Blogbeitrag ansehen. Es gibt nicht viele Interaktionen zu erkennen, wir müssen unsere DOM-Operationen nicht optimieren. Wenn wir einen neuen Blogbeitrag laden, können wir einfach das DOM zerschlagen und neu aufbauen.
document.querySelector('body').innerHTML = PostPage(postData);
Wir könnten dies ein wenig schöner machen, indem wir es in eine Funktion verpacken
function update() {
document.querySelector('body').innerHTML = PostPage(postData);
}
Jetzt können wir, wann immer wir einen neuen Blogbeitrag laden, einfach update() aufrufen und er erscheint. Wenn unsere Anwendung kompliziert genug wäre, dass sie häufig neu gerendert werden müsste – vielleicht ein paar Mal pro Sekunde in bestimmten Situationen – würde sie sehr schnell ruckeln. Sie könnten komplexe Logik schreiben, um herauszufinden, welche Teile der Seite bei einer bestimmten Datenänderung wirklich aktualisiert werden müssen und nur diese aktualisieren, aber das ist der Punkt, an dem Sie einfach ein Framework verwenden sollten.
Nicht nur für Inhalte
An diesem Punkt wurde fast unser gesamter Rendering-Code verwendet, um den tatsächlichen HTML- und Textinhalt innerhalb der Elemente zu bestimmen, aber wir müssen nicht dort aufhören. Da wir nur einen HTML-String erstellen, ist alles darin möglich. CSS-Klassen?
function BlogPost(postData) {
return `<div class="post ${postData.isSponsored ? 'sponsored-post' : ''}">
<h1>
${postData.title} ${postData.isSponsored ? '<img src="badge.png">' : ''}
</h1>
<h3>By ${postData.author}</h3>
<p>${postData.body}</p>
</div>`;
}
Check. HTML-Attribute?
function BlogPost(postData) {
return `<div class="post ${postData.isSponsored ? 'sponsored-post' : ''}">
<input type="checkbox" ${postData.isSponsored ? 'checked' : ''}>
<h1>
${postData.title} ${postData.isSponsored ? '<img src="badge.png">' : ''}
</h1>
<h3>By ${postData.author}</h3>
<p>${postData.body}</p>
</div>`;
}
Check. Fühlen Sie sich frei, hier wirklich kreativ zu werden. Denken Sie über Ihre Daten nach und darüber, wie alle verschiedenen Aspekte davon in Markup dargestellt werden sollten, und schreiben Sie Ausdrücke, die das eine in das andere verwandeln.
Zusammenfassung
Hoffentlich gibt Ihnen dieser Beitrag ein gutes Werkzeugset für das Schreiben einfacher reaktiver, datengesteuerter Weboberflächen ohne den Overhead von Werkzeugen oder Frameworks. Dieser Code ist weitaus einfacher zu schreiben und zu warten als jQuery-Spaghetti, und es gibt absolut keine Hürde, ihn jetzt zu verwenden. Alles, worüber wir hier gesprochen haben, ist kostenlos in allen einigermaßen modernen Browsern enthalten, nicht einmal eine Bibliothek.
Teil 2 konzentriert sich auf klassenbasierte, zustandsbehaftete Komponenten, die in das Gebiet des zu komplizierten, um es vernünftigerweise in VanillaJS zu tun, vordringen werden. Aber beim Teufel, wir werden es trotzdem versuchen, und es wird interessant werden.
Artikelserie
- Rein funktionaler Stil (Du bist hier!)
- Klassenbasierte Komponenten
Ausgezeichneter Beitrag. Ich werde dies zur Pflichtlektüre für meine React-Studenten machen, denn auch wenn sie oft zu React greifen, ermöglicht das Verständnis dessen, was ein Werkzeug für einen tut, die bessere und klügere Nutzung dieses Werkzeugs.
Ausgezeichneter Artikel…
Ich habe das genossen und freue mich darauf, diesen Ansatz auszuprobieren. Vielen Dank!
Hehe, gut gemacht, habe das schon oft und lange benutzt, sogar mit JQuery.
Und die Leistung ist ziemlich gut (habe 1 MB JSON verwendet, um einige Bäume zu generieren).
Aber wie du planst – es wird mit ES6-Klassen viel übersichtlicher sein :D
Das ist sehr hilfreich, um besser zu verstehen, wie JS-Frameworks im Hintergrund funktionieren und warum sie überhaupt nützlich sind.
Es gibt einen weiteren, eher „progressiv erweiterten“ Ansatz, den ich bei der Arbeit verwende. Anstatt das gesamte HTML mit JavaScript zu rendern, baue ich bei der ersten Anfrage wie üblich mein gesamtes HTML serverseitig auf, aber ich verwende eine PHP-Klasse, um jede Komponente der Benutzeroberfläche separat mit eigener Controller-Logik, View/Template-Datei, JS und CSS-Datei zu rendern.
Auf diese Weise werden alle HTML, JS und CSS für eine einzelne Seite/Benutzeroberfläche beim ersten Aufruf serverseitig gerendert, ohne Verzögerung. Wenn ich dann die Ansicht aktualisieren muss, kann ich eine Ajax-Anfrage erstellen, um nur eine dieser Komponenten nach der anderen zu aktualisieren. Anstatt reines Daten von Ajax zurückzugeben und das HTML mühsam in JavaScript zu rekonstruieren, rendere ich die einzelne Komponente serverseitig neu und gebe das HTML als Element eines JSON-Arrays zurück (dadurch kann ich auch reine Daten im selben Request/Response-Array zurückgeben, um einen anderen Teil der Seite bei Bedarf sofort zu aktualisieren).
Durch die weitere Implementierung eines „Hijax“-Ansatzes für Formularübermittlungen kann dies zu einer vollständig progressiv verbesserten Anwendung führen, die auch ohne JavaScript funktioniert.
Ich verwende ProcessWire (http://www.processwire.com) als Backend dafür, aber ich bin sicher, eine ähnliche Strategie könnte mit einer anderen Plattform oder gar keiner Plattform verwendet werden.
Das ist genau das Material, auf das ich mich gerade konzentriere – Vanilla JS verwenden, um die Grundlagen der Frontend-Entwicklung aufzufrischen und sich nicht immer auf Frameworks verlassen.
Ich freue mich auf den zweiten Teil dieser Serie!
Was ist der Vorteil, dies clientseitig zu tun? Anstatt zum Beispiel im WordPress-Template über PHP?
Ist es rein für den nächsten Schritt (Teil 2), wo Interaktion hinzugefügt wird? Zum jetzigen Zeitpunkt sieht dies nur nach statischem Inhalt aus und wäre für Suchmaschinen nicht lesbar.
Meiner Meinung nach ist diese Art der Entwicklung am besten, wenn man keine Möglichkeit hat, Backend-Code bereitzustellen. Wie in SharePoint Online oder anderen SAAS-Umgebungen.
Es macht im Grunde genau dasselbe wie PHP, aber auf der Clientseite. Es könnte nützlich sein, zum Beispiel, wenn ein Benutzer auf einen Link zu einem anderen Blogbeitrag klickt. Anstatt zu einer komplett separaten Seite zu gehen, könnten Sie einfach JavaScript verwenden, um die neuen Beitragsdaten zu laden und dann nur den Hauptabschnitt dynamisch neu zu befüllen. Es ist erwähnenswert, dass diese Technik nicht unbedingt auf der Root-Seite verwendet werden muss; es könnte einfach eine gute Möglichkeit sein, zustandslose Unterabschnitte der Seite neu zu rendern, möglicherweise sogar in Kombination mit jQuery. Und mit oder ohne jQuery funktionieren Event-Handler auf die gleiche Weise (obwohl Sie sie jedes Mal neu anhängen müssten, wenn Sie das DOM neu aufbauen). Es ist nicht so, dass dies nicht interaktiv sein kann, es ist nur, dass es für Websites mit sparsamer Interaktion besser geeignet ist; Sie würden zum Beispiel nicht jedes Mal neu rendern wollen, wenn ein Eingabefeld wie in React geändert wird.
Sie haben Recht bezüglich des Suchmaschinenproblems. Eine Umgehungslösung, wenn Sie Node.js als Backend verwenden, könnte darin bestehen, Seiten von Anfang an serverseitig zu rendern und sie auf der Clientseite neu zu rendern. Da Ihre Vorlagen in JavaScript sind, könnten sie genauso gut in Node wie im Browser ausgewertet werden, sodass Sie keine Duplizierung haben.
Ich stimme vollkommen zu, ich habe mich gefragt, warum man jQuery dafür benutzen würde, und mir ist gerade eingefallen, dass es nur statisches HTML ist.
Aber wie @Vanderson sagt, freue ich mich darauf, das alles in Teil 2 zu aktualisieren.
In letzter Zeit verlassen sich die Leute oft auf Frameworks, ohne überhaupt über den primären Weg nachzudenken, Dinge zu tun. Hier wird dem Browser unnötige Arbeit überlassen, die der Server hätte erledigen sollen.
Einfaches, altes HTML ist das Leichteste, was der Browser parsen kann.
@Vanderson – Ich stimme Ihrem SEO-Punkt zu (von Spiders lesbar) und man sollte keine clientseitige Vorlagengestaltung verwenden, wenn man gutes SEO haben möchte (obwohl Engines darin immer besser werden, insbesondere Google kann tatsächlich auch AJAX-generierte Seiten crawlen und wird darin immer besser).
Aber wenn man etwas wie eine SPA hinter einem Login baut, ist es viel einfacher (und das Neuladen ganzer Seiten in einer SPA ist nichts, was man will, oder?).
Außerdem gibt es noch andere Kompromisse – wie isomorphen Rendering (JavaScript serverseitig gerendert), der SEO-Probleme auch löst.
Ich muss nur erwähnen, dass Browser heute hochgradig für JavaScript optimiert sind und manchmal ist es sogar schneller, eine Seite clientseitig zu rendern (wie ich schon sagte – das Rendern eines sehr großen Baumes funktionierte in meinem Fall mit JS, basierend auf JSON, das im Backend generiert wurde, viel besser).
Vielen Dank. Dieser Artikel hat meinen Horizont erweitert, was die Funktionsweise von Frameworks im Hintergrund und ihre Nützlichkeit betrifft.
Ich benutze VUE.js wegen seiner Einfachheit. Ich werde das bald ausprobieren.
Toller Artikel. Die Präferenz für die Wahl neuer Technologie besteht darin, die Vorteile der neuesten Verbesserungen auf diesem Gebiet zu genießen. Gleichzeitig sind die Risiken hoch. Ein klares Gleichgewicht zwischen beiden kann erreicht werden, indem man sich darauf konzentriert, wie man bestehende Technologie optimiert, um die neuen Funktionen zu nutzen. Als Entwickler gibt mir das eine andere Dimension. Danke fürs Teilen.
Guter Artikel, ich warte bereits auf den zweiten Teil!
Bis jetzt habe ich so ziemlich nichts über den Grund für all diese Frameworks verstanden. Ein riesiges Dankeschön an Sie, Chris und Sacha für diese Serie. Machen Sie weiter so.
Array.map, Array.forEach sind Teil von ES5, nicht ES6.
Haben Sie sich SAM.js angesehen? Es ist die funktionale reaktive Antwort auf MVC.
sam.js.org
Leser Jussi Hartzell schreibt
Ich wünschte, Sie würden den Artikel https://css-tricks.de/reactive-uis-vanillajs-part-1-pure-functional-style/ aktualisieren, um HTML-Escaping hinzuzufügen. Leute kopieren und fügen diese Dinge oft ein, um sie auf ihren Websites zu verwenden. Ich sehe das sehr oft bei Leuten, die über die Erstellung von HTML-Strings bloggen. Wenn Ihre Daten Zeichen enthalten, die in HTML maskiert werden müssen, wird Ihr HTML kaputtgehen. Es gibt auch Möglichkeiten für Angriffe wie das Einschleusen von Skript-Tags usw. Diese Zeichenfolgen sollten immer maskiert werden.
Mit Template-Strings ist eine Tag-Funktion ziemlich einfach.
Der Code für htmlEscape stammt von hier: https://basarat.gitbooks.io/typescript/docs/template-strings.html
Wenn Sie Code verwenden möchten, der innere Template-Literale verwendet, sollten Sie htmlEscape so ändern, dass es keine Arrays maskiert. Dann könnten Sie Dinge wie diese schreiben