Geh weg von jQuery nach Svelte

Hallo alle zusammen.

Dies ist eine Fortsetzung des Artikels " Geh weg von jQuery nach Svelte, kein Schmerz ."

Im Folgenden werde ich über die Schwierigkeiten sprechen, auf die ich gestoßen bin, es gab nicht viele von ihnen, und nur eine war so grundlegend, dass ich ohne die Unterstützung der Gemeinschaft nicht fertig werden konnte.

Einführung


Ich hatte vor, das Front-End in Teilen umzuschreiben. Es würde überhaupt nicht funktionieren. Es hat nicht vollständig funktioniert. Ich musste es in großen Teilen umschreiben.

Erstens ist der Svelte-Ansatz deklarativ, da der jQuery-Ansatz unbedingt erforderlich ist.

Zweitens, da unser Bereich mit jQuery immer global ist, können wir von jeder Codezeile aus auf alle Elemente einer Webseite zugreifen. Wir greifen über die ID oder den CSS-Selektor darauf zu, während Svelte die Verwendung von Komponenten und innerhalb der angezeigten Komponente empfiehlt Nur die Komponente selbst, wir haben keine externen oder internen Elemente und können nicht direkt darauf zugreifen.

Mit Svelte erhalten wir eine echte OOP: Wir können keine Änderungen selbst vornehmen, wir können der Komponente nur die Notwendigkeit von Änderungen mitteilen. Wie diese Änderungen vorgenommen werden, kennt nur der Code innerhalb der Komponente.

Und das ist großartig :)

Svelte verfügt über zwei Mechanismen zur Kommunikation mit Komponenten.

Bindungsvariablen (Bindungen, Mapping)


Wir deklarieren eine Variable und ordnen sie dem Komponentenattribut zu:

<script>
    import DetailTaskView from './DetailTaskView.svelte';
    let task = {};
    let isModal = false;
    function renderTask(data) {
        const isSuccess = data.hasOwnProperty(0);
        if (isSuccess) {
            isModal = true;
            task = data[0];
        }
    }
    import {fade} from 'svelte/transition';
</script>
{#if isModal}
    <div transition:fade>
        <DetailTaskView bind:isModal="{isModal}" {...task}/>
    </div>
{/if}

Was haben wir getan?


Wir haben zwei lokale Variablen als "Aufgabe" und "isModal" deklariert. "Aufgabe" sind Informationen, die in der Komponente angezeigt werden sollen. Daten werden nur angezeigt und werden nicht geändert. "IsModal" ist das Flag für die Sichtbarkeit der Komponenten. Wenn der Benutzer auf das Kreuz auf der Komponente geklickt hat, sollte die Komponente verschwinden Da das Kreuz zur Komponente gehört, wissen wir nichts über den Klick, aber wir erfahren, dass sich der Wert der Variablen "isModal" geändert hat, und dank der Reaktivität werden wir diesen neuen Wert berechnen.

Wenn wir eine bidirektionale Bindung benötigen, schreiben wir "bind:". Eine Änderung des Werts innerhalb der Komponente wird an die "übergeordnete" Komponente gemeldet.

Wir können eine abgekürzte Form verwenden, wenn wir der Komponente nur die Werte mitteilen müssen, und wenn der Name des Attributs der Komponente mit dem Namen der Variablen übereinstimmt, können wir "{task}" schreiben oder den Destruktor "{... task}" verwenden.

Praktisch.

Wenn jedoch eine andere Komponente in eine Komponente eingebettet ist und es auch eine dritte gibt, gibt es natürlich ein Bollerplate zum Scrollen von Werten in der Verschachtelungshierarchie nach oben und unten.

Ereignis sprudelt


Ich kann mich mit der Terminologie irren, nicht viel treten.

Die übergeordnete Komponente kann die Ereignisse der untergeordneten Komponente verarbeiten, jedoch nur die Ereignisse, die die untergeordnete Komponente meldet.

<!-- App.svelte   -->
<script>
    import SearchForm from './SearchForm.svelte';
    async function applySample(event) {
        const sample = event.detail.sample;
        if(sample){
            search(sample);
        }
        if(!sample){
            renderPage();
        }
    }
</script>
<div class="container">
    <h1>  </h1>
    <SearchForm on:search={applySample}/>
</div>

<!-- SearchForm.svelte    -->
<script>
	import { createEventDispatcher } from 'svelte';
	const dispatch = createEventDispatcher();
	let sample = '';
    function search(event) {
        event.preventDefault();
        dispatch('search', {
            sample: sample
        });
    }
</script>
<form class="form-horizontal" id="search"
on:submit={search}>
    <div class="form-group">
        <label class="control-label col-sm-2" for="sample">
        
        </label>
        <div class="col-sm-10">
            <input id="sample" class="form-control" type="search"
             placeholder="  "
             autocomplete="on" bind:value={sample}
             />
        </div>
    </div>
</form>

Was ist denn hier los ?


In der übergeordneten Komponente wird die Funktion "applySample" vom Ereignis "on: search" der untergeordneten Komponente "SearchForm" ausgeführt. Diese Funktion empfängt die Parameter (event.detail) vom Ereignisobjekt und verarbeitet sie.

Was passiert in einer Komponente?


Das Attribut "value" des Eingabeelements wird der Variablen "sample" zugeordnet. Durch das Ereignis "on: submit" (des Elements "form") wird die Funktion "search" ausgeführt, die das Ereignis "search" auslöst und das Objekt {sample: sample in die Eigenschaft "detail" schreibt } - das ist der Wert der Suchzeichenfolge.

Somit wird der Wert der Suchzeichenfolge an die übergeordnete Komponente übergeben, und er entscheidet, was mit diesem Wert geschehen soll.

Die Komponente ist nur für die Anzeige des Eingabeformulars und die Übermittlung des eingegebenen Werts verantwortlich. Die Komponente implementiert die Suche und Anzeige der Ergebnisse nicht, daher teilen wir die Verantwortung.

Die Schönheit!

Der Übergang vom Imperativ zum Deklarativ


Hier funktioniert es leider nicht, den Unterschied genauso deutlich zu zeigen. In Worten, es klingt so: Wenn ich bei der Verwendung von jQuery ein HTML-Markup erstellt und es dann an der richtigen Stelle eingefügt habe, generiere ich mit Svelte ein Array mit den Attributen der Komponenten und füge dann in der Schleife die Komponenten mit vorberechneten Attributen hinzu:

<!-- Paging.svelte        -->
<script>
    import {createEventDispatcher} from 'svelte';
    import OrdinalPlace from './OrdinalPlace.svelte';
    let pagingPlaces;
    //         pagingPlaces
    function addPlace(
        paging = [], index = Number.NEGATIVE_INFINITY,
        text = "", css = "") {
        paging.push({index:index,text:text,css:css});

        return paging;
    }
    const dispatch = createEventDispatcher();
    function browsePage(event) {
        const pageIndex = event.detail.index;
        dispatch('move', {
            index: pageIndex
        });
    }
</script>

{#if pagingPlaces.length}
    <table class = "table table-hover-cells table-bordered">
        <tbody>
            <tr>
            {#each pagingPlaces as place (place.index)}
                <OrdinalPlace on:move="{browsePage}"
                {...place}>
                </OrdinalPlace>
            {/each}
            </tr>
        </tbody>
    </table>
{/if}

<!-- OrdinalPlace.svelte     ""      -->
<script>
    export let index = -1;
    export let text = "";
    export let css = "";

    let number = index +1;
    function skip() {
        return !(text === "");
    }

    let letSkip = skip();
    let noSkip = !letSkip;

    import { createEventDispatcher } from "svelte";
    const dispatch = createEventDispatcher();
    function moveTo() {
        if(noSkip){
            dispatch("move", {index:index});
        }
    }
</script>
<td class="{css}" on:click="{moveTo}">
    {#if letSkip}
        {text}
    {/if}
    {#if noSkip}
        {number}
    {/if}
</td>

Wie es funktioniert ?


Beim Erstellen der Paging-Komponente bilden wir ein Array von „Elementen“, um zu bestimmten Seiten zu gelangen - „pagingPlaces“ -, durchlaufen dann alle Elemente und fügen eine Komponente ein, um eine Paging-Position anzuzeigen - „OrdinalPlace“.

Wieder ein deklarativer Ansatz, wir bilden nicht jede Position selbst, wir sagen der Komponente, dass wir eine Position mit solchen Attributen anzeigen müssen.

Hier sehen wir einen verwirrten Fall der Entstehung eines Ereignisses. Um zur Suchergebnisseite zu gelangen, klickt der Benutzer auf die Komponente "OrdinalPlace". Diese Komponente kann die Seite nicht laden. Daher wird ein "Verschieben" -Ereignis mit dem Parameter "Seitenindex" erstellt. Dieses Ereignis nimmt die übergeordnete Komponente "Paging" auf, die die Seite daher auch nicht laden kann Es löst das 'Verschieben'-Ereignis aus, und die nächste übergeordnete Komponente nimmt es bereits auf und verarbeitet es irgendwie.

Svelte und der Komponentenansatz zwingen uns, Verantwortung zu teilen und SOLID zu folgen.

Größter Hinterhalt


Das obige Beispiel zeigt eine Lösung für ein grundlegendes Problem, das ich ohne einen Hinweis nicht lösen könnte. Svelte speichert alle Komponenten zwischen, und Sie müssen ihm helfen, Änderungen an diesen Komponenten zu verfolgen.

Hier ist der fragliche Code:

            {#each pagingPlaces as place (place.index)}
                <OrdinalPlace on:move="{browsePage}"
                {...place}>
                </OrdinalPlace>
            {/each}

Um die Liste der Seiten im Paging anzuzeigen, haben wir das Array durchlaufen und Svelte hat jeder Komponente einen Array-Index zugewiesen. Jetzt trifft Svelte die Entscheidung, die Komponente basierend auf diesem Index neu zu zeichnen. Wenn Sie den Index beim Durchlaufen der Array-Elemente nicht angeben, verstehen Sie nicht, was Ich versuchte einen Tag lang zu verstehen, dann bat ich die Halle um Hilfe und in der Halle fand ich nicht sofort eine Person, die mit diesem Rechen gut vertraut war, aber sie halfen mir dank der Jungs.

Beachten Sie beim Arbeiten mit Arrays Folgendes: Bei jedem Durchlauf durch das Array muss erneut ein Index verwendet werden:

            {#each pagingPlaces as place (place.index)}

"PagingPlaces als Ort (place.index)" - verwenden Sie unbedingt.

Wenn Sie zuvor mit React / Vue gearbeitet haben, sind Sie mit dieser Funktion wahrscheinlich bereits vertraut.

Visuelle Effekte


Meine Anwendung verwendete modale Fenster. jQuery legt hierfür die Markup-Anforderungen fest. Ohne diese Funktion funktioniert die Methode jQuery.modal () nicht.

Svelte macht das einfacher:

{#if isModal}
    <div transition:fade>
        <DetailTaskView bind:isModal="{isModal}" {...task}/>
    </div>
{/if}

Insbesondere ist "Transition: Fade" für das Verschwinden / Erscheinen von Elementen auf der Seite verantwortlich.
Niemand schreibt uns vor, welchen Aufschlag wir haben sollen.

Das ist gut.

Zusätzlich zu dieser Animation hat Svelte noch ein paar mehr: Fliegen und Tweened , Beispiele aus den Links im Tutorial.

Andere


Variablennamen


Bei der Benennung von Variablen / Parametern / Attributen müssen Sie ein Wort verwenden, um sowohl die Eigenschaft des Objekts als auch die dort geschriebene Variable, die Mobilteilregel, aufzurufen, wenn Sie über den Code am Telefon sprechen müssen, damit Sie an diesem Ende nicht verwirrt werden und alles verstehen, wie wiederholte Namen verletzen.

Ajax


Dies gilt nicht für Svelte, betrifft jedoch die Ablehnung der Verwendung von jQuery. JQuery.ajax kann durch fetch () ersetzt werden. Ich habe einen solchen Ersatz vorgenommen. Sie können ihn im Repository sehen.

Fazit


Um von jQuery zu Svelte zu wechseln, muss die Logik zum Erstellen von Markups neu geschrieben werden. Dies ist jedoch nicht so schwierig und so lange es scheint, insbesondere wenn Ihr Code damit nicht sündigt.

Svelte vereinfacht Ihr Markup und verkürzt den JS-Code. Durch die Verwendung von Svelte wird Ihr Code wiederverwendbarer und widerstandsfähiger gegen zufällige Fehler.

Verwenden Sie Svelte, es wird gut für Sie und Ihre Kunden sein!

Verweise


Offizielle Website von Svelte
Repository mit dem Übergang von der Verwendung von jQuery zur Verwendung von Svelte
Channel der russischsprachigen Community Svelte in Telegram

Vielen Dank für das Lesen.

PS: Ich weiß nicht, warum Habr den Doppelpunkt vom Link zum Community-Kanal ausschließt. Die richtige Linkzeile lautet: tg: // resolve? Domain = sveltejs

All Articles