Warum JavaScript HTML verschlingt: Codebeispiele

Die Webentwicklung entwickelt sich ständig weiter. In letzter Zeit ist ein Trend populär geworden, der im Wesentlichen der allgemein akzeptierten Idee der Entwicklung von Webanwendungen widerspricht. Einige haben große Hoffnungen auf ihn, während andere enttäuscht sind. Jeder hat seine eigenen Gründe dafür, die auf den Punkt gebracht schwer zu erklären sind.



Webseitencode besteht traditionell aus drei Abschnitten, von denen jeder seine Aufgaben erfüllt: HTML-Code definiert die Struktur und Semantik, CSS-Code bestimmt das Erscheinungsbild und JavaScript-Code bestimmt sein Verhalten. In Teams mit Designern, HTML / CSS-Entwicklern und JavaScript-Entwicklern ist diese Trennung selbstverständlich: Designer definieren visuelle Elemente und eine Benutzeroberfläche, HTML- und CSS-Entwickler platzieren diese visuellen Elemente auf einer Seite in einem Browser und JavaScript-Entwickler fügen Benutzerinteraktionen hinzu binde alles zusammen und "lass es funktionieren". Jeder kann an seinen Aufgaben arbeiten, ohne den Code der beiden anderen Entwicklerkategorien zu beeinträchtigen. All dies gilt jedoch für den sogenannten "alten Stil".

In den letzten Jahren haben JavaScript-Entwickler begonnen, die Struktur der Seite in JavaScript und nicht in HTML zu bestimmen (z. B. mithilfe des React js-Frameworks ), was die Erstellung und Pflege von Benutzerinteraktionscode vereinfacht. Ohne js Frameworks ist die Entwicklung moderner Websites viel schwieriger. Wenn Sie jemandem sagen, dass der von ihm geschriebene HTML-Code in Teile zerlegt und mit JavaScript gemischt werden muss, mit dem er sehr vertraut ist, kann dies (aus offensichtlichen Gründen) mit Feindseligkeit wahrgenommen werden. Zumindest wird der Gesprächspartner fragen, warum wir das überhaupt brauchen und wie wir davon profitieren werden.

Als JavaScript-Entwickler in einem funktionsübergreifenden Team wird mir diese Frage manchmal gestellt, und oft fällt es mir schwer, sie zu beantworten. Alle Materialien, die ich zu diesem Thema gefunden habe, wurden für ein Publikum geschrieben, das bereits mit JavaScript vertraut ist. Und das ist nicht sehr gut für diejenigen, die sich ausschließlich auf HTML und CSS spezialisiert haben. Aber das HTML-in-JS-Muster (oder etwas anderes, das die gleichen Vorteile bietet) ist wahrscheinlich für einige Zeit gefragt, daher denke ich, dass dies eine wichtige Sache ist, die jeder, der an der Webentwicklung beteiligt ist, verstehen sollte.

In diesem Artikel werde ich Codebeispiele für Interessierte geben, aber mein Ziel ist es, diesen Ansatz so zu erklären, dass er ohne sie verstanden werden kann.

Likbez: HTML, CSS und JavaScript


Um das Publikum dieses Artikels zu maximieren, möchte ich kurz darauf eingehen, welche Rolle diese Sprachen bei der Erstellung von Webseiten spielen und welche Art von Trennung zwischen ihnen ursprünglich bestand. Wenn Sie dies alle wissen, können Sie diesen Abschnitt überspringen.

HTML: fĂĽr Struktur und Semantik


HTML-Code (HyperText Markup Language) definiert die Struktur und Semantik des Inhalts, der auf der Seite platziert wird. Der HTML-Code dieses Artikels enthält beispielsweise den Text, den Sie gerade lesen, und gemäß der angegebenen Struktur wird dieser Text in einem separaten Absatz nach der Überschrift und vor dem Einfügen von CodePen platziert .

Erstellen Sie beispielsweise eine einfache Webseite mit einer Einkaufsliste:



Wir können diesen Code in einer Datei speichern, in einem Webbrowser öffnen und der Browser zeigt das Ergebnis an. Wie Sie sehen können, ist der HTML-Code in diesem Beispiel eine Seite mit der Überschrift „Einkaufsliste“ (Einkaufsartikel (2 Artikel)), einem Eingabetextfeld, einer Schaltfläche „Artikel hinzufügen“ und einer Liste mit zwei Artikeln („Eier“). und "Öl"). Der Benutzer gibt die Adresse in seinen Webbrowser ein, dann fordert der Browser diesen HTML-Code vom Server an, lädt ihn herunter und zeigt ihn an. Wenn die Liste bereits Elemente enthält, kann der Server wie in diesem Beispiel HTML mit vorgefertigten Elementen senden.

Geben Sie etwas in das Eingabefeld ein und klicken Sie auf die Schaltfläche "Element hinzufügen". Sie werden sehen, dass nichts passiert. Die Schaltfläche ist keinem Code zugeordnet, der HTML ändern könnte, und HTML kann selbst nichts ändern. Wir werden gleich darauf zurückkommen.

CSS: um das Aussehen zu ändern


Der CSS-Code (Cascading Style Sheets) definiert das Erscheinungsbild der Seite. Das CSS dieses Artikels definiert beispielsweise die Schriftart, den Abstand und die Farbe des Textes, den Sie lesen.

Möglicherweise haben Sie bemerkt, dass unser Beispiel für eine Einkaufsliste sehr einfach aussieht. In HTML können keine Abstände, Schriftgrößen und Farben angegeben werden. Deshalb verwenden wir CSS. Wir könnten CSS-Code für diese Seite hinzufügen, um sie ein wenig zu dekorieren:



Wie Sie sehen können, hat dieser CSS-Code die Größe und Dicke der Textzeichen sowie die Hintergrundfarbe geändert. Ein Entwickler kann analog Regeln für seinen eigenen Stil schreiben, die nacheinander auf jede HTML-Struktur angewendet werden: Wenn wir dieser Seite Abschnitts-, Schaltflächen- oder ul- Elemente hinzufügen , gelten dieselben Schriftartenänderungen.
Die Schaltfläche Element hinzufügen bewirkt jedoch immer noch nichts: Hier benötigen wir nur JavaScript.

JavaScript: um Verhalten zu implementieren


JavaScript-Code definiert das Verhalten interaktiver oder dynamischer Elemente auf einer Seite. Beispielsweise wird CodePen mit JavaScript geschrieben.

Damit die Schaltfläche Element hinzufügen in unserem Beispiel ohne JavaScript funktioniert, müssen wir speziellen HTML-Code verwenden, um das Zurücksenden von Daten an den Server zu erzwingen ( <form action \ u003d '...'>, wenn Sie plötzlich interessiert sind). Darüber hinaus lädt der Browser die aktualisierte Version der gesamten HTML-Datei neu, ohne den aktuellen Status der Seite zu speichern. Wenn diese Einkaufsliste Teil einer großen Webseite wäre, würde alles verloren gehen, was der Benutzer getan hat. Es spielt keine Rolle, wie viele Pixel Sie beim Lesen des Textes nach unten verschoben haben. Wenn Sie den Server neu starten, kehren Sie zum Anfang zurück. Es spielt keine Rolle, wie viele Minuten des Videos Sie sich angesehen haben. Beim Neustart wird es erneut gestartet.

So funktionierten früher alle Webanwendungen: Jedes Mal, wenn ein Benutzer mit einer Webseite interagierte, schien er seinen Webbrowser zu schließen und erneut zu öffnen. Dies ist für eine einfache Fallstudie nicht sehr wichtig, aber für eine große komplexe Seite, deren Laden einige Zeit in Anspruch nehmen kann, ist dieser Ansatz weder für den Browser noch für den Server effektiv.

Wenn wir etwas auf der Seite ändern möchten, ohne diese Seite vollständig neu zu laden, müssen wir JavaScript verwenden:



Wenn wir nun den Text in das Eingabefeld eingeben und auf die Schaltfläche Element hinzufügen klicken, wird unser neues Element zur Liste hinzugefügt und die Anzahl der Elemente oben aktualisiert! In einer realen Anwendung würden wir auch Code hinzufügen, um ein neues Element im Hintergrund an den Server zu senden, damit es beim nächsten Laden der Seite angezeigt wird.

Die Trennung von JavaScript von HTML und CSS ist auch in diesem einfachen Beispiel gerechtfertigt. Komplexere Interaktionen funktionieren folgendermaßen: HTML wird geladen und angezeigt, und anschließend wird JavaScript gestartet, um etwas hinzuzufügen und zu ändern. Mit zunehmender Komplexität der Webanwendung müssen wir jedoch sorgfältig überwachen, was, wo und wann sich unser JavaScript-Code ändert.

Wenn wir diese App mit einer Einkaufsliste weiterentwickeln, können wir Schaltflächen hinzufügen, um Artikel zu bearbeiten oder aus der Liste zu entfernen. Angenommen, wir schreiben JavaScript-Code für eine Schaltfläche, mit der ein Element gelöscht wird. Vergessen Sie jedoch, Code hinzuzufügen, der Informationen über die Gesamtzahl der Elemente oben auf der Seite aktualisiert. Plötzlich wird eine Fehlermeldung angezeigt: Nachdem der Benutzer den Artikel gelöscht hat, stimmt die auf der Seite angegebene Gesamtzahl nicht mit der Liste überein!

Sobald wir den Fehler bemerkten, haben wir ihn behoben, indem wir dieselbe Zeile totalText.innerHTML aus unserem Code für Artikel hinzufügen zum Code für Artikel entfernen hinzugefügt haben. Jetzt haben wir den gleichen Code, der an mehreren Stellen dupliziert wird. Nehmen wir später an, wir möchten diesen Code so ändern, dass anstelle von "(2 Elemente)" oben auf der Seite "Elemente: 2" angezeigt wird. Wir müssen sicherstellen, dass wir nicht vergessen, diesen Code an allen drei Stellen zu aktualisieren: in HTML, im JavaScript-Code für die Schaltfläche Element hinzufügen und im JavaScript-Code für die Schaltfläche Element entfernen. Wenn wir dies nicht tun, wird ein weiterer Fehler auftreten, aufgrund dessen sich dieser Text nach der Interaktion mit dem Benutzer dramatisch ändert.

Bereits in diesem einfachen Beispiel sehen wir, wie leicht es ist, im Code verwirrt zu werden. Na sicher. Es gibt Ansätze und Vorgehensweisen zur Optimierung des JavaScript-Codes, um die Lösung dieses Problems zu vereinfachen. Wenn die Dinge jedoch komplizierter werden, müssen wir das Projekt weiter umstrukturieren und ständig neu schreiben, damit es leicht entwickelt und gewartet werden kann. Während HTML und JavaScript getrennt gespeichert werden, kann es sehr aufwändig sein, die Synchronisation zwischen beiden sicherzustellen. Dies ist einer der Gründe, warum neue JavaScript-Frameworks wie React populär geworden sind: Sie sollen eine formalere und effizientere Beziehung zwischen HTML und JavaScript ermöglichen. Um zu verstehen, wie dies funktioniert, müssen wir uns zunächst etwas eingehender mit der Informatik befassen.

Imperative vs deklarative Programmierung


Der Schlüssel zum Verständnis ist der Unterschied im Denken. In den meisten Programmiersprachen können Sie nur einem Paradigma folgen, obwohl einige von ihnen zwei gleichzeitig unterstützen. Es ist wichtig, beide Paradigmen zu verstehen, um den Hauptvorteil von HTML-in-JS aus der Sicht eines JavaScript-Entwicklers zu erkennen.

  • . «» , . ( ) : , , . , , . - «». Vanilla JavaScript , jQuery. JavaScript .
    • « X, Y, Z».
    • : , .selected; , .selected.

  • . , . , , «» (), , - . , . (, React), , , . , , , , . , :
    • « XYZ. , , .
    • Beispiel: Dieses Element hat eine .selected-Klasse, wenn der Benutzer sie ausgewählt hat.


HTML ist eine deklarative Sprache


Vergessen Sie JavaScript für einen Moment. Hier ist eine wichtige Tatsache: HTML ist eine deklarative Sprache. In der HTML-Datei können Sie Folgendes deklarieren:

<section>
  <h1>Hello</h1>
  <p>My name is Mike.</p>
</section>

Wenn der Webbrowser diesen HTML-Code liest, ermittelt er unabhängig die erforderlichen Schritte und führt sie aus:

  1. Erstellen Sie ein Abschnittselement .
  2. Erstellen Sie ein Header-Element der Ebene 1 ( h1 ).
  3. Setzen Sie den Titelelementtext auf „Hallo“.
  4. Platzieren Sie das Titelelement im Abschnittselement.
  5. Erstellen Sie ein Absatzelement ( p ).
  6. Setzen Sie den Text des Absatzelements auf "Mein Name ist Mike".
  7. Platzieren Sie ein Absatzelement in einem Abschnittselement .
  8. Platzieren Sie das Abschnittselement in einem HTML-Dokument.
  9. Zeigen Sie das Dokument auf dem Bildschirm an.

Für einen Webentwickler spielt es keine Rolle, wie genau der Browser diese Dinge tut: Alles, was zählt, ist, was er tut. Dies ist ein großartiges Beispiel, um den Unterschied zwischen den beiden Programmierparadigmen zu veranschaulichen. Kurz gesagt, HTML ist eine deklarative Abstraktion, die sich um eine unbedingt implementierte Webbrowser-Rendering-Engine dreht. Er kümmert sich darum, wie, also müssen Sie sich nur um was kümmern. Sie können das Leben genießen, während Sie deklaratives HTML schreiben, da die guten Leute von Mozilla, Google und Apple bei der Erstellung Ihres Webbrowsers wichtigen Code für Sie geschrieben haben.

JavaScript ist eine zwingende Sprache


Wir haben bereits im obigen Einkaufslistenbeispiel ein einfaches Beispiel für zwingendes JavaScript untersucht, und ich habe beschrieben, wie sich die Komplexität der Anwendungsfunktionen auf den Aufwand für deren Implementierung und die Wahrscheinlichkeit von Fehlern bei dieser Implementierung auswirkt.

Schauen wir uns nun eine etwas komplexere Aufgabe an und sehen, wie sie mit einem deklarativen Ansatz vereinfacht werden kann. Stellen Sie sich eine Webseite vor, die Folgendes enthält:

  • eine Liste von gekennzeichneten Flags, von denen jede Zeile bei Auswahl ihre Farbe ändert;
  • Text unten, zum Beispiel "1 von 4 ausgewählt", der aktualisiert werden sollte, wenn die Flags geändert werden;
  • Klicken Sie auf die Schaltfläche Alle, die deaktiviert werden sollte, wenn alle Kontrollkästchen bereits aktiviert sind.
  • Klicken Sie auf die Schaltfläche Keine, die deaktiviert werden sollte, wenn die Kontrollkästchen nicht aktiviert sind.

Hier ist eine Implementierung in einfachem HTML, CSS und zwingendem JavaScript:



const captionText = document.getElementById('caption-text');
const checkAllButton = document.getElementById('check-all-button');
const uncheckAllButton = document.getElementById('uncheck-all-button');
const checkboxes = document.querySelectorAll('input[type="checkbox"]');

function updateSummary() {
  let numChecked = 0;
  checkboxes.forEach(function(checkbox) {
    if (checkbox.checked) {
      numChecked++;
    }
  });
  captionText.innerHTML = `${numChecked} of ${checkboxes.length} checked`;
  if (numChecked === 0) {
    checkAllButton.disabled = false;
    uncheckAllButton.disabled = true;
  } else {
    uncheckAllButton.disabled = false;
  }
  if (numChecked === checkboxes.length) {
    checkAllButton.disabled = true;
  }
}

checkAllButton.addEventListener('click', function() {
  checkboxes.forEach(function(checkbox) {
    checkbox.checked = true;
    checkbox.closest('tr').className = 'checked';
  });
  updateSummary();
});

uncheckAllButton.addEventListener('click', function() {
  checkboxes.forEach(function(checkbox) {
    checkbox.checked = false;
    checkbox.closest('tr').className = '';
  });
  updateSummary();
});

checkboxes.forEach(function(checkbox) {
  checkbox.addEventListener('change', function(event) {
    checkbox.closest('tr').className = checkbox.checked ? 'checked' : '';
    updateSummary();
  });
});

Kopfschmerzen wie sie sind


Um diese Funktion mit zwingendem JavaScript zu implementieren, mĂĽssen wir dem Browser einige detaillierte Anweisungen geben. Dies ist eine verbale Beschreibung des Codes aus dem obigen Beispiel.
In unserem HTML deklarieren wir die ursprĂĽngliche Seitenstruktur:
  • Es gibt vier Zeilenelemente (eine Zeile einer Tabelle, es ist eine Liste), von denen jedes ein Flag enthält. Das dritte Flag ist markiert.
  • Es ist ein Text "1 von 4 ausgewählt".
  • Es gibt eine Schaltfläche Alle auswählen, die aktiviert ist.
  • Es gibt eine Schaltfläche "Keine auswählen", die deaktiviert ist.

In unserem JavaScript schreiben wir Anweisungen, was geändert werden muss, wenn jedes dieser Ereignisse eintritt:
Wenn ein Flag von unmarkiert zu markiert wechselt:
  • Suchen Sie die Zeile mit dem Kontrollkästchen und fĂĽgen Sie die ausgewählte CSS-Klasse hinzu.
  • Suchen Sie alle Flags in der Liste und berechnen Sie, wie viele davon markiert sind und wie viele nicht.
  • Suchen Sie den Text und aktualisieren Sie ihn unter Angabe der korrekten Anzahl ausgewählter Einkäufe und ihrer Gesamtzahl.
  • Suchen Sie die Schaltfläche Keine auswählen und aktivieren Sie sie, wenn sie deaktiviert wurde.
  • Wenn jetzt alle Kontrollkästchen aktiviert sind, suchen Sie die Schaltfläche Alle auswählen und deaktivieren Sie sie.

Wenn eine Flagge von markiert zu nicht markiert wechselt:
  • Suchen Sie die Zeile mit dem Flag und entfernen Sie die ausgewählte Klasse.
  • Suchen Sie alle Kontrollkästchen in der Liste und berechnen Sie, wie viele davon aktiviert sind und wie viele nicht.
  • Suchen Sie das Textelement fĂĽr den Lebenslauf und aktualisieren Sie es mit der verifizierten Nummer und Summe.
  • Suchen Sie die Schaltfläche Alle auswählen und aktivieren Sie sie, wenn sie deaktiviert wurde.
  • Wenn alle Kontrollkästchen deaktiviert sind, suchen Sie die Schaltfläche Keine auswählen und deaktivieren Sie sie.

Wenn die Schaltfläche Alle auswählen gedrückt wird:
  • Suchen Sie alle Kontrollkästchen in der Liste und markieren Sie sie.
  • Suchen Sie alle Zeilen in der Liste und fĂĽgen Sie ihnen die ausgewählte Klasse hinzu.
  • Suchen Sie den Text und aktualisieren Sie ihn.
  • Suchen Sie die Schaltfläche Alle auswählen und deaktivieren Sie sie.
  • Suchen Sie die Schaltfläche Keine auswählen und aktivieren Sie sie.

Wenn die Schaltfläche Keine auswählen gedrückt wird:
  • Suchen Sie alle Kontrollkästchen in der Liste und deaktivieren Sie alle Kontrollkästchen.
  • Suchen Sie alle Zeilen in der Liste und entfernen Sie die ausgewählte Klasse aus ihnen.
  • Suchen Sie das Textelement fĂĽr den Lebenslauf und aktualisieren Sie es.
  • Suchen Sie die Schaltfläche Alle auswählen und aktivieren Sie sie.
  • Suchen Sie die Schaltfläche Keine auswählen und deaktivieren Sie sie.

Wow ... das ist viel, oder? Nun, wir sollten besser nicht vergessen, Code für alle möglichen Situationen zu schreiben. Wenn wir eine dieser Anweisungen vergessen oder durcheinander bringen, wird eine Fehlermeldung angezeigt: Die Gesamtsummen stimmen nicht mit den Kontrollkästchen überein, oder die Schaltfläche wird aktiviert, die nichts bewirkt, wenn Sie darauf klicken, oder die ausgewählte Zeile erhält die falsche Farbe oder etwas anderes noch, worüber wir nicht nachgedacht haben und erst wissen werden, wenn sich der Benutzer beschwert.

Wir haben hier wirklich ein großes Problem: Es gibt keine Entität, die vollständige Informationen über den Staat enthalten würdeunserer Anwendung (in diesem Fall ist dies die Antwort auf die Frage „Welche Flags sind markiert?“) und wäre für die Aktualisierung dieser Informationen verantwortlich. Flags wissen natürlich, ob sie aktiviert sind, aber der CSS-Code für die Zeilen der Tabelle, des Textes und jeder Schaltfläche sollte dies ebenfalls wissen. Fünf Kopien dieser Informationen werden im gesamten HTML-Code separat gespeichert. Wenn sie sich an einer dieser Stellen ändern, muss der JavaScript-Entwickler diese abfangen und wichtigen Code schreiben, um sie mit Änderungen an anderen Stellen zu synchronisieren.

Und dies ist immer noch ein einfaches Beispiel für eine kleine Seitenkomponente. Stellen Sie sich vor, wie komplex und fragil eine größere Webanwendung wird, wenn Sie all dies in zwingendem JavaScript implementieren müssen, auch wenn diese Anweisungen wie Kopfschmerzen aussehen. Für viele komplexe, moderne Webanwendungen lässt sich diese Lösung nicht vom Wort "vollständig" skalieren.

Wir suchen nach der Quelle der Wahrheit


Tools wie React ermöglichen die deklarative Verwendung von JavaScript. So wie HTML eine deklarative Abstraktion über die Anweisungen zum Anzeigen in einem Webbrowser ist, ist React eine deklarative Abstraktion über JavaScript.

Denken Sie daran, wie HTML es uns ermöglicht, uns auf die Struktur der Seite anstatt auf Implementierungsdetails zu konzentrieren, und wie der Browser diese Struktur anzeigt. Wenn wir React verwenden, können wir uns auf die Struktur konzentrieren und sie basierend auf Daten definieren, die an einem Ort gespeichert sind. Dieser Prozess wird als Einwegbindung bezeichnet, und der Speicherort der Anwendungsstatusdaten wird als "einzige Quelle der Wahrheit" bezeichnet. Wenn sich die Quelle der Wahrheit ändert, aktualisiert React automatisch die Seitenstruktur für uns. Er wird sich hinter den Kulissen um die erforderlichen Schritte kümmern, wie es ein Webbrowser für HTML tut. Obwohl hier React als Beispiel verwendet wird, funktioniert dieser Ansatz auch für andere Frameworks wie Vue.

Kehren wir zu unserer Liste der Kontrollkästchen aus dem obigen Beispiel zurück. In diesem Fall ist die „Wahrheit“, die wir wissen wollen, ziemlich kurz: Welche Flags werden überprüft? Andere Details (z. B. Text, Linienfarbe, welche Schaltflächen aktiviert sind) sind bereits Informationen, die auf der Grundlage der Wahrheitsquelle erhalten wurden. Und warum sollten sie eine eigene Kopie dieser Informationen haben? Sie sollten einfach eine einzige schreibgeschützte Wahrheitsquelle verwenden, und alle Seitenelemente sollten „nur wissen“, welche Kontrollkästchen aktiviert sind, und sich entsprechend verhalten. Sie können sagen, dass Tabellenzeilen, Text und Schaltflächen automatisch auf ein Kontrollkästchen reagieren können sollten, je nachdem, ob es aktiviert ist oder nicht ("Sehen Sie, was dort passiert?").

Sag mir was du willst (was du wirklich willst)


Um diese Seite mit React zu implementieren, können wir die Liste durch einige einfache Faktenbeschreibungen ersetzen:

  • Es gibt eine Liste von True / False-Werten mit dem Namen checkboxValues, die anzeigt, welche Felder markiert sind.
    • Beispiel: checkboxValues ​​\ u003d [false, false, true, false]
    • Diese Liste zeigt, dass wir vier Flags haben, nur das dritte ist gesetzt.

  • FĂĽr jeden Wert in checkboxValues ​​in der Tabelle gibt es eine Zeile, die:
    • hat eine CSS-Klasse namens .selected, wenn der Wert true ist, und
    • enthält ein Flag, das ĂĽberprĂĽft wird, ob der Wert wahr ist.

  • Es gibt ein Textelement, das den Text "{x} von {y} selected" enthält, wobei {x} die Anzahl der wahren Werte in checkboxValues ​​und {y} die Gesamtzahl der Werte in checkboxValues ​​ist.
  • Es gibt eine Schaltfläche Alle auswählen, die aktiviert ist, wenn checkboxValues ​​falsche Werte hat.
  • Select None, , checkboxValues ​​ true.
  • , checkboxValues.
  • Select All , checkboxValues ​​ true.
  • Select None checkboxValues ​​ false.

Sie werden feststellen, dass die letzten drei Absätze immer noch zwingende Anweisungen sind („Wenn dies passiert, tun Sie es“), aber dies ist der einzige zwingende Code, den wir schreiben müssen. Dies sind drei Codezeilen, die alle eine einzige Quelle der Wahrheit aktualisieren.

Der Rest sind deklarative Anweisungen ("es gibt ..."), die jetzt direkt in die Definition der Seitenstruktur integriert werden. Zu diesem Zweck schreiben wir Code für unsere Elemente mit einer speziellen JavaScript-Syntaxerweiterung - JavaScript XML (JSX). Es ähnelt HTML: Mit JSX können Sie die Struktur der Benutzeroberfläche mithilfe von HTML-ähnlicher Syntax sowie mit regulärem JavaScript beschreiben. Dies ermöglicht es uns, JS-Logik mit der HTML-Struktur zu mischen, sodass die Struktur jederzeit unterschiedlich sein kann. Es hängt alles vom Inhalt der CheckboxValues ​​ab.

Wir schreiben unser Beispiel fĂĽr React um:



function ChecklistTable({ columns, rows, initialValues, ...otherProps }) {
  const [checkboxValues, setCheckboxValues] = React.useState(initialValues);
  
  function checkAllBoxes() {
    setCheckboxValues(new Array(rows.length).fill(true));
  }
  
  function uncheckAllBoxes() {
    setCheckboxValues(new Array(rows.length).fill(false));
  }
  
  function setCheckboxValue(rowIndex, checked) {
    const newValues = checkboxValues.slice();
    newValues[rowIndex] = checked;
    setCheckboxValues(newValues);
  }
  
  const numItems = checkboxValues.length;
  const numChecked = checkboxValues.filter(Boolean).length;
  
  return (
    <table className="pf-c-table pf-m-grid-lg" role="grid" {...otherProps}>
      <caption>
        <span>{numChecked} of {numItems} items checked</span>
        <button
          onClick={checkAllBoxes}
          disabled={numChecked === numItems}
          className="pf-c-button pf-m-primary"
          type="button"
        >
          Check all
        </button>
        <button
          onClick={uncheckAllBoxes}
          disabled={numChecked === 0}
          className="pf-c-button pf-m-secondary"
          type="button"
        >
          Uncheck all
        </button>
      </caption>
      <thead>
        <tr>
          <td />
          {columns.map(function(column) {
            return <th scope="col" key={column}>{column}</th>;
          })}
        </tr>
      </thead>
      <tbody>
        {rows.map(function(row, rowIndex) {
          const [firstCell, ...otherCells] = row;
          const labelId = `item-${rowIndex}-${firstCell}`;
          const isChecked = checkboxValues[rowIndex];
          return (
            <tr key={firstCell} className={isChecked ? 'checked' : ''}>
              <td className="pf-c-table__check">
                <input
                  type="checkbox"
                  name={firstCell}
                  aria-labelledby={labelId}
                  checked={isChecked}
                  onChange={function(event) {
                    setCheckboxValue(rowIndex, event.target.checked);
                  }}
                />
              </td>
              <th data-label={columns[0]}>
                <div id={labelId}>{firstCell}</div>
              </th>
              {otherCells.map(function(cell, cellIndex) {
                return (
                  <td key={cell} data-label={columns[1 + cellIndex]}>
                    {cell}
                  </td>
                );
              })}
            </tr>
          );
        })}
      </tbody>
    </table>
  );
};

function ShoppingList() {
  return (
    <ChecklistTable
      aria-label="Shopping list"
      columns={['Item', 'Quantity']}
      rows={[
        ['Sugar', '1 cup'],
        ['Butter', '½ cup'],
        ['Eggs', '2'],
        ['Milk', '½ cup'],
      ]}
      initialValues={[false, false, true, false]}
    />
  );
}

ReactDOM.render(
  <ShoppingList />,
  document.getElementById('shopping-list')
);


JSX sieht eigenartig aus. Als ich das zum ersten Mal sah, schien es mir einfach unmöglich, dies zu tun. Meine erste Reaktion war: „Was? HTML darf nicht im JavaScript-Code enthalten sein! “ Und ich war nicht der einzige. Dies ist jedoch kein HTML, sondern JavaScript, das als HTML verkleidet ist. In der Tat ist dies eine leistungsstarke Lösung.

Erinnern Sie sich an die 20 oben genannten zwingenden Anweisungen? Jetzt haben wir drei davon. Die restlichen (internen) Imperativanweisungen React selbst werden für uns hinter den Kulissen ausgeführt - jedes Mal, wenn sich die CheckboxWerte ändern.

Mit diesem Code kann die Situation nicht mehr auftreten, wenn der Text oder die Farbe der Zeile nicht mit den Kontrollkästchen übereinstimmt oder wenn die Schaltfläche aktiviert ist, obwohl sie deaktiviert sein sollte. Es gibt eine ganze Kategorie von Fehlern, die in unserer Webanwendung jetzt einfach nicht mehr auftreten können. Alle Arbeiten werden auf der Grundlage einer einzigen Quelle der Wahrheit ausgeführt, und wir Entwickler können weniger Code schreiben und nachts besser schlafen. Zumindest JavaScript-Entwickler ...

JavaScript besiegte HTML: verhungert


Da Webanwendungen immer komplexer werden, wird es immer schmerzhafter, die klassische Aufgabentrennung zwischen HTML und JavaScript beizubehalten. HTML wurde ursprĂĽnglich fĂĽr statische Webseiten entwickelt. Um dort komplexere interaktive Funktionen hinzuzufĂĽgen, muss die entsprechende Logik in imperativem JavaScript implementiert werden, das mit jeder Codezeile immer verwirrender und fragiler wird.

Vorteile des modernen Ansatzes: Vorhersagbarkeit, Wiederverwendbarkeit und Kombination


Die Fähigkeit, eine einzige Quelle der Wahrheit zu verwenden, ist der wichtigste Vorteil dieses Modells, hat aber auch andere Vorteile. Das Definieren unserer Seitenelemente in JavaScript-Code bedeutet, dass wir Komponenten (einzelne Blöcke einer Webseite) wiederverwenden können, sodass wir denselben HTML-Code nicht an mehreren Stellen kopieren und einfügen können. Wenn wir eine Komponente ändern müssen, ändern Sie einfach ihren Code an nur einer Stelle. In diesem Fall treten Änderungen in allen Kopien der Komponente auf (innerhalb einer oder sogar in vielen Webanwendungen, wenn in ihnen wiederverwendbare Komponenten verwendet werden).

Wir können einfache Komponenten wie LEGO-Würfel zusammensetzen und so komplexere und nützlichere Komponenten erstellen, ohne dass ihre Logik zu verwirrend wird. Und wenn wir Komponenten verwenden, die von anderen Entwicklern erstellt wurden, können wir problemlos Updates oder Fehlerbehebungen zusammenstellen, ohne unseren Code neu schreiben zu müssen.

Das gleiche JavaScript, nur im Profil


Diese Vorteile haben einen Nachteil. Es gibt gute Gründe, warum Menschen die Trennung von HTML und JavaScript schätzen. Wie bereits erwähnt, erschwert das Aufgeben regulärer HTML-Dateien den Workflow für jemanden, der zuvor noch nicht mit JavaScript gearbeitet hat. Diejenigen, die zuvor unabhängig Änderungen an der Webanwendung vornehmen konnten, müssen jetzt zusätzliche komplexe Fähigkeiten erwerben, um ihre Autonomie zu bewahren oder sogar im Team zu platzieren.

Es gibt auch technische Mängel. Beispielsweise akzeptieren einige Tools, wie z. B. Linters und Parser, nur normales HTML als Eingabe, und die Arbeit mit JavaScript-Plug-Ins von Drittanbietern ist möglicherweise schwieriger. Darüber hinaus ist JavaScript nicht die beste Sprache, aber es ist ein einheitlicher Standard, der für Webbrowser akzeptiert wird. Neue Tools und Funktionen machen es besser, aber es gibt noch einige Fallstricke, die Sie kennen müssen, bevor Sie damit arbeiten.

Ein weiteres potenzielles Problem: Wenn die semantische Struktur der Seite in abstrakte Komponenten zerlegt wird, denkt der Entwickler möglicherweise nicht mehr darüber nach, welche HTML-Elemente als Ergebnis generiert werden. Bestimmte HTML-Tags wie Abschnitt und beiseitehaben ihre eigene Semantik, die bei der Verwendung von Allzweck-Tags wie div und span verloren geht - auch wenn sie auf der Seite optisch gleich aussehen. Dies ist besonders wichtig, um die Verfügbarkeit der Webanwendung für verschiedene Benutzerkategorien sicherzustellen.

Dies wirkt sich beispielsweise auf das Verhalten des Bildschirmlesegeräts für Benutzer mit Sehbehinderung aus. Vielleicht sind dies nicht die interessantesten Aufgaben für den Entwickler, aber JavaScript-Entwickler sollten immer daran denken, dass die Beibehaltung der Semantik von HTML in diesem Fall die wichtigste Aufgabe ist .

Bewusstes BedĂĽrfnis gegen unbewussten Trend


In letzter Zeit ist die Verwendung von Frameworks in jedem Projekt zu einem Trend geworden. Einige Leute glauben, dass die Trennung von HTML und JavaScript veraltet ist, aber nicht. Für eine einfache statische Website, die keine komplizierte Benutzerinteraktion erfordert, ist dies genau richtig. Begeisterte React-Fans mögen mir hier nicht zustimmen, aber wenn Ihr JavaScript nur eine nicht interaktive Webseite erstellt, sollten Sie sie nicht verwenden. JavaScript wird nicht so schnell geladen wie normales HTML. Wenn Sie also nicht die Aufgabe festlegen, neue Entwicklungserfahrungen zu sammeln oder die Zuverlässigkeit des Codes zu verbessern, kann JavaScript hier mehr schaden als nützen.

Darüber hinaus müssen Sie nicht Ihre gesamte Website in React schreiben. Oder Vue! Oder was gibt es sonst noch ... Viele Leute wissen das nicht, weil alle Tutorials im Grunde zeigen, wie man React verwendet, um eine Site von Grund auf neu zu entwickeln. Wenn Sie nur ein kleines komplexes Widget auf einer einfachen Website haben, können Sie React für eine Komponente verwenden . Sie müssen sich nicht immer um Webpack, Redux, Gatsby oder andere Dinge kümmern, die jemand dort als "Best Practices" empfiehlt.

Wenn die Anwendung jedoch recht komplex ist, lohnt es sich absolut, einen modernen deklarativen Ansatz zu verwenden. Ist React die beste Lösung? Nein. Er hat bereits starke Konkurrenten. Und dann wird immer mehr auftauchen ... Aber die deklarative Programmierung wird nirgendwo hingehen, und in einem neuen Rahmen wird dieser Ansatz wahrscheinlich noch besser überdacht und umgesetzt.


All Articles