Afaste-se do jQuery e do Svelte, por assim dizer

Olá a todos.

Esta é uma continuação do artigo " Afaste-se do jQuery e do Svelte, sem problemas ".

Abaixo, vou falar sobre as dificuldades que encontrei, não foram muitas, e apenas uma foi tão fundamental que eu não aguentaria sem o apoio da comunidade .

Introdução


Planejei reescrever o front-end em pedaços, não era algo que não desse certo, não deu certo - tive que reescrever em pedaços grandes.

Primeiro, como a abordagem jQuery é imperativa, a abordagem Svelte é declarativa.

Em segundo lugar, como usando o jQuery, nosso escopo é sempre global, podemos acessar todos os elementos de uma página da web a partir de qualquer linha de código, acessá-los por seletor de ID ou CSS, enquanto Svelte recomenda o uso de componentes e dentro do componente que vemos somente o componente em si, não temos elementos externos ou internos e não podemos acessá-los diretamente.

Com o Svelte, obtemos OOP real: não podemos fazer alterações sozinhos, podemos apenas dizer ao componente sobre a necessidade de alterações. Como essas alterações serão feitas, conhece apenas o código dentro do componente.

E isso é ótimo :)

O Svelte possui dois mecanismos de comunicação com os componentes.

Variáveis ​​de ligação (ligações, mapeamento)


Declaramos uma variável e a mapeamos para o atributo component:

<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}

O que nos fizemos?


Declaramos duas variáveis ​​locais “task” e “isModal”, “task” são informações a serem exibidas no componente, os dados são exibidos apenas, não serão alterados, “isModal” é o sinalizador de visibilidade do componente, se o usuário clicar na cruz do componente, o componente deverá desaparecer , a cruz pertence ao componente, por isso não sabemos nada sobre o clique, mas aprendemos que o valor da variável "isModal" mudou e, graças à reatividade, elaboraremos esse novo valor.

Se precisarmos de ligação bidirecional, escreveremos "bind:", uma alteração no valor dentro do componente será relatada ao componente "pai".

Podemos usar um formulário abreviado se precisarmos apenas informar os valores aos componentes e se o nome do atributo do componente corresponder ao nome da variável, podemos escrever "{task}" ou usar o destruidor "{... task}".

Convenientemente.

Mas se tivermos outro componente incorporado em um componente e também houver um terceiro, é claro que haverá um exemplo de rolagem de valores para cima e para baixo na hierarquia de aninhamento.

Evento borbulhando


Eu posso estar enganado com a terminologia, não chute muito.

O componente pai pode manipular os eventos do componente filho, mas apenas os eventos relatados pelo componente filho.

<!-- 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>

O que está acontecendo aqui ?


No componente pai, a função "applySample" é executada pelo evento "on: search" do componente filho "SearchForm". Essa função recebe os parâmetros (event.detail) do objeto de evento e os processa.

O que acontece em um componente?


O atributo “value” do elemento de entrada é mapeado para a variável “sample”, pelo evento “on: submit” (do elemento “form”), a função “search” é executada, o que eleva o evento 'search' e grava o objeto {sample: sample na propriedade "detail" } - ou seja, o valor da sequência de pesquisa.

Assim, o valor da cadeia de pesquisa é passado para o componente pai e é ele quem decide o que fazer com esse valor.

O componente é o único responsável por exibir o formulário de entrada e transmitir o valor inserido, o componente não implementa a pesquisa e a exibição dos resultados, por isso compartilhamos a responsabilidade.

A beleza!

A transição do imperativo para o declarativo


Infelizmente, aqui não funciona para mostrar a diferença tão claramente. Em palavras, soa assim: se, ao usar o jQuery, criei a marcação html e a inseri no lugar certo, em seguida, com o Svelte, gero uma matriz com os atributos dos componentes e, no loop, adiciono os componentes com os atributos pré-calculados:

<!-- 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>

Como funciona ?


Ao criar o componente Paginação, formamos uma matriz de "elementos" para acessar determinadas páginas - "pagingPlaces", depois percorremos todos os elementos e inserimos um componente para exibir uma posição de paginação - "OrdinalPlace".

Novamente, uma abordagem declarativa, não formamos cada posição por nós mesmos, dizemos ao componente que precisamos exibir uma posição com esses atributos.

Aqui vemos um caso confuso do surgimento de um evento. Para ir para a página de resultados da pesquisa, o usuário clica no componente "OrdinalPlace", este componente não pode carregar a página, portanto, cria um evento "move" com o parâmetro de índice da página e esse evento seleciona o componente pai - "Paginação", que também não pode carregar a página. ele gera o evento 'move', e o próximo componente pai já o pega e, de alguma forma, o processa.

A abordagem Svelte e a componente nos levam a compartilhar responsabilidades e seguir o SOLID.

Maior emboscada


O exemplo acima mostra uma solução para um problema fundamental que eu não seria capaz de lidar sem uma dica. O Svelte armazena em cache todos os componentes e você precisa ajudá-lo a rastrear alterações nesses componentes.

Aqui está o código em questão:

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

Para exibir a lista de páginas na paginação, percorremos a matriz e o Svelte atribuiu a um componente um índice de matriz para cada componente, agora o Svelte decide redesenhar o componente com base nesse índice, se você não especificar o índice enquanto itera os elementos da matriz, então não entenderá o que , Tentei entender por um dia, depois pedi ajuda ao corredor e no corredor não encontrei imediatamente uma pessoa que conhecia bem esse ancinho, mas eles me ajudaram, graças aos rapazes.

Ao trabalhar com matrizes, lembre-se disso: qualquer passagem pela matriz deve usar um índice, novamente:

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

"PagingPlaces as place (place.index)" - não se esqueça de usar.

Obviamente, se você já trabalhou com o React / Vue, provavelmente já deve estar familiarizado com esse recurso.

Efeitos visuais


Meu aplicativo usou janelas modais. O jQuery para isso define os requisitos de marcação, sem ele, o método jQuery.modal () não funcionará.

O Svelte facilita isso:

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

Especificamente, "transição: desaparecer" é responsável pelo desaparecimento / aparência de elementos na página.
Ninguém nos dita que marcação devemos ter.

É bom.

Além dessa animação, Svelte tem um par mais: mosca e interpolados , exemplos dos links no tutorial.

De outros


Nomes de variáveis


O problema com a nomeação de variáveis ​​/ parâmetros / atributos, você precisa usar uma palavra para chamar a propriedade do objeto e a variável que você escreve lá, a regra do aparelho quando você precisa falar sobre o código no telefone, para que você não fique confuso nesse fim e entenda tudo, nomes repetidos violar.

Ajax


Isso não se aplica ao Svelte, mas diz respeito à rejeição do uso do jQuery, o jQuery.ajax pode ser substituído por fetch (). Fiz essa substituição, você pode vê-la no repositório.

Conclusão


Passar do jQuery para o Svelte exigirá reescrever a lógica da criação da marcação, mas não é tão difícil e contanto que pareça, especialmente se o seu código não estiver errado com isso.

O Svelte simplifica sua marcação e reduz o código JS, usando o Svelte torna seu código mais reutilizável e resistente a erros aleatórios.

Use o Svelte, será bom para você e seus clientes!

Referências


Site oficial do Svelte
Repository com a transição do jQuery para o Svelte
Channel da comunidade de língua russa Svelte in Telegram

Obrigado por ler.

PS: Não sei por que Habr exclui os dois pontos do link para o canal da comunidade, a linha de link correta é: tg: // resolve? Domain = sveltejs

All Articles