Обновление: я обновил этот проект анимацией и исправил логику приложения. Вы можете найти самую последнюю версию здесь и живую демо.

Я много слышал о Svelte и, послушав этот доклад, тоже захотел попробовать. Я так и сделал, и оказалось, что Svelte супер потрясающий. Я привык программировать на React, и некоторые явные отличия заставили меня полюбить Svelte.

Что такое Svelte

Svelte - это компилятор, который преобразует наш декларативный компонентный код в JavaScript, который может напрямую управлять DOM. Возможно, вы слышали, что Svelte работает быстро, быстрее, чем любой другой фреймворк, и это правда. Причина этого в том, что Svelte больше похож на компилятор, чем на фреймворк или библиотеку. Svelte не использует Shadow DOM или Virtual DOM для выполнения обновлений DOM, что, естественно, делает его на порядки быстрее, чем фреймворки или библиотеки, которые поставляются с реализацией виртуальной DOM. Он пытается избавиться от большого количества шаблонного кода и является действительно реактивным. Если вы пришли из экосистемы React, как я, Svelte во многих отношениях бросает вызов вашему образу мышления.

В этой статье мы создадим небольшое приложение-викторину и посмотрим, как Svelte сравнивается с React.

Начнем с создания проекта Svelte. Svelte, как и create-react-app, предоставляет способ начальной загрузки приложения Svelte. Просто запустите приведенный ниже код, чтобы начать работу.

npx degit sveltejs/template my-svelte-project 
cd my-svelte-project 
npm install 
npm run dev

Каталог нашего проекта должен выглядеть примерно так.

Теперь, если вы откроете package.json, вы увидите нечто удивительное.

В нем нет ни одного dependencies. Все зависимости devDependencies. Это связано с тем, что Svelte - это компилятор, и все зависимости вычисляются заранее при генерации сборки, и, следовательно, наш окончательный код не поставляется с какой-либо из этих зависимостей, что делает размер нашей сборки намного меньше.

  • Файл main.js - это наша основная точка входа в приложение. Это похоже на файл App.js в проекте React.
  • Мы также видим файл App.svelte. Давайте откроем файл и разберемся в его различных частях.
  • Если вы знакомы с React, мы знаем, что мы обычно заканчиваем наши файлы React расширением .jsx. Точно так же в Svelte все наши файлы, относящиеся к Svelte, заканчиваются расширением .svelte.
  • Каждый файл Svelte содержит либо только markup (HTML tags), либо разметку со стилями, заключенными в тег <style></style>, или JavaScript, заключенный в тег <script></script>, или все три из них.
  • Самое лучшее в компоненте Svelte - это то, что стили внутри них привязаны только к этому компоненту, и, следовательно, вы не столкнетесь с проблемой, когда стили будут просачиваться в какой-либо другой компонент.
  • Если вы привыкли писать HTML на JS с JSX, Svelte - полная противоположность этому, и вы пишете все в svelte файле, который является просто синтаксическим сахаром для записи HTML файлов.

Примечание. Если вы работаете в среде React, возможно, вы не привыкли так думать, но поверьте мне, это поможет вам расширить свои границы.

С учетом сказанного давайте начнем.

Сначала мы посмотрим на файл App.svelte. Это наш основной файл / компонент, который служит точкой входа для приложения. Вы можете использовать приведенный ниже код для справки.

<script>
  // import QuizArea from './QuizArea.svelte';
</script>

<style>
  main {
    text-align: center;
    padding: 1em;
    max-width: 240px;
    margin: 0 auto;
  }

  h1 {
    text-transform: uppercase;
    font-size: 4em;
    font-weight: 100;
  }

  @media (min-width: 640px) {
    main {
      max-width: none;
    }
  }
</style>

<main>
  <!-- <QuizArea></QuizArea> -->
</main>
  • Как вы можете видеть в коде, у нас есть script, style и markup для компонента. На этом этапе код не делает ничего особенного, кроме просто применения некоторых стилей к приложению.
  • Но скоро мы раскомментируем компонент QuizArea.

Я надеюсь, что вы получили общее представление о различных частях файла / компонента Svelte.

Я не добавил все файлы проекта в этот пост, но если вы захотите в любой момент сослаться на код, он доступен здесь.

Теперь давайте создадим новый QuizArea компонент. Для этого создайте файл с именем QuizArea.svelte в каталоге src.

Мы рассмотрим каждую из трех частей отдельно.

  • Сначала у нас есть тег <styles></styles>. Вы можете добавить любые стили для этого компонента между тегом <style>.
  • Вместо того, чтобы записывать CSS в отдельный файл, в Svelte мы пишем стили внутри самого компонента.
  • Я определил стили для компонента QuizArea в приведенном ниже коде, но вы можете оформить его так, как хотите.
<style>
  #main {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translateX(-50%) translateY(-50%);
    height: calc(100vh - 40%);
    width: calc(100vw - 40%);
    padding: 15px;

    background-color: white;
    border-radius: 6px;
    box-shadow: 0 0 5px white;

    text-align: left;
  }

  span {
    display: block;
    margin-top: 20px;
  }

  button {
    margin-top: 15px;
    margin-right: 15px;
    padding: 10px;
    float: right;

    color: white;
    background-color: #ff3e00;
    border: none;
    border-radius: 10px;
    cursor: pointer;
  }

  button:hover {
    box-shadow: 0 0 5px #ff3e00;
  }

  #heading {
    font-size: 24px;
    font-weight: bolder;
  }

  #difficulty {
    position: absolute;
    right: 16px;
    top: 16px;
    height: 25px;
    width: 80px;
    padding: 5px;

    background: rgb(97, 225, 230);
    color: white;
    text-align: center;
    border-radius: 16px;
  }

  #category {
    font-size: 12px;
    font-weight: normal;
  }

  #button-bar {
    position: absolute;
    bottom: 16px;
    right: 0;
  }

  #choice {
    margin-top: 16px;
    padding: 8px;

    border: 1px solid #4e5656;
    border-radius: 8px;
  }

  #choice:hover {
    cursor: pointer;
    background: green;
    border: 1px solid green;
    color: white;
  }

  #snackbar {
    position: absolute;
    left: 16px;
    bottom: 16px;
  }
</style>

Это было легко, ничего особенного или особенного. Единственное, что мы пишем styles в том же файле, что и код другого компонента.

  • Далее мы поговорим о теге <script></script>. Мы будем писать весь наш JavaScript внутри этого тега, и здесь мы посмотрим, как Svelte делает что-то.
  • Итак, в Svelte мы будем использовать let или const для объявления переменных. Все переменные, которые мы объявляем, являются важными state переменными. К этим переменным применяются все правила JavaScript, поэтому const переменные нельзя переназначить, а let переменные можно переназначить.
  • Они такие же, как переменные, которые мы объявляем с помощью useState() в React.
  • Самое лучшее в Svelte - это то, что компонент автоматически перерисовывается всякий раз, когда изменяется значение переменной состояния. Но вызывать какие-либо set функции нет необходимости.
// In Svelte
let name = 'Manan';

// Same thing in React
const [name, setName] = React.useState('Manan');

// causes component to re-render
name = 'Maitry';

// Same thing in React
setName('Maitry');
  • Мы говорили о state, поэтому естественно, что мы говорим о props. В Svelte вы можете объявить опору, просто добавив ключевое слово export после объявления переменной.
// props in Svelte
export let name;
  • Теперь опору name можно использовать в других компонентах. Мы можем объявить любое количество props, как мы это делаем в React.
  • Мы даже можем объявить functions, который может действовать как наш event handlers или может служить любой другой цели, например, получение данных, выполнение служебных операций и т. Д.
// on click handler
function handleClick(change) {
  snackbarVisibility = false;

  if (change === 'f') questionNo += 1;
  else questionNo -= 1;

  question = htmlDecode(data[questionNo].question);
  answerChoices = shuffle(
    [
      ...data[questionNo].incorrect_answers,
      data[questionNo].correct_answer
    ].map(a => htmlDecode(a))
  );
  answer = htmlDecode(data[questionNo].correct_answer);
  category = htmlDecode(data[questionNo].category);
  difficulty = data[questionNo].difficulty;
}
  • Мы можем импортировать другие модули, пакеты или компоненты, используя ключевое слово import. Это похоже на то, что мы делаем в React.
// imports the Snackbar component
import Snackbar from './Snackbar.svelte';

Главный вывод из этой части состоит в том, что мы можем писать все, что захотим, с помощью нескольких ухищрений, а все остальное компилятор сделает за нас.

Теперь вопрос в том, как мы можем использовать наши переменные JavaScript в разметке HTML. Итак, в последней части приложения мы рассмотрим это.

  • Отрендерить любую переменную довольно просто. Мы просто заключаем переменную в фигурные скобки, как это {variableName}.
<!-- see how simple it is :smiley:-->
<p>Hello {name}!</p>

<!-- outputs -->
Hello Manan
  • Помните, что разметка внутри файла Svelte - это Html-код, и поэтому мы можем использовать встроенные выражения Svelte для выполнения таких вещей, как рендеринг чего-либо условного или циклического перебора заданных значений.
  • Для условного рендеринга мы используем {#if expression}<div></div> {/if}. Здесь expression может быть любой допустимой переменной или выражением, которое находится в области видимости (т. Е. Объявлено внутри тега <script>).
{#if name}
<div id="snackbar">
  <Snackbar message="{correct}"></Snackbar>
</div>
{/if}
  • Чтобы перебрать массив, мы используем {#each expression as exp}<div></div>{/each}. Здесь expression - это итеративное значение, а exp - это каждая запись этого итеративного значения.
{#each answerChoices as choice}
<div id="choice" on:click="{(e) => handleAnswerChoice(e)}">
  <i>{choice}</i>
</div>
{/each}

Это только верхушка айсберга, и вы можете узнать больше обо всем, что может делать Svelte, здесь.

Теперь мы можем сшить наш компонент вместе. Скопируйте и вставьте приведенный ниже код в свой QuizArea.svelte файл.

<script>
  import { onMount } from 'svelte';
  import { htmlDecode, shuffle } from './utils.js';
  import Snackbar from './Snackbar.svelte';

  let data;

  let questionNo = 0;
  let question = 'loading...';
  let answerChoices;
  let answer;
  let category = 'loading...';
  let difficulty = 'loading...';

  let correct = false;
  let snackbarVisibility = false;
  $: score = 0;

  // function for fetching data
  function fetchData() {
    fetch('https://opentdb.com/api.php?amount=10')
      .then(resp => resp.json())
      .then(res => {
        data = res.results;
        question = htmlDecode(data[questionNo].question);
        answerChoices = shuffle(
          [
            ...data[questionNo].incorrect_answers,
            data[questionNo].correct_answer
          ].map(a => htmlDecode(a))
        );
        answer = htmlDecode(data[questionNo].correct_answer);
        category = htmlDecode(data[questionNo].category);
        difficulty = data[questionNo].difficulty;
      })
      .catch(e => console.error(e));
  }

  onMount(fetchData);

  // function for moving onto next/prev question
  function handleClick(change) {
    snackbarVisibility = false;

    if (change === 'f') questionNo += 1;
    else questionNo -= 1;

    question = htmlDecode(data[questionNo].question);
    answerChoices = shuffle(
      [
        ...data[questionNo].incorrect_answers,
        data[questionNo].correct_answer
      ].map(a => htmlDecode(a))
    );
    answer = htmlDecode(data[questionNo].correct_answer);
    category = htmlDecode(data[questionNo].category);
    difficulty = data[questionNo].difficulty;
  }

  // function to check the correctness of an answer
  function handleAnswerChoice(e) {
    if (e.target.innerText === answer && !correct) {
      correct = true;
      score += 1;
    } else if (correct) correct = false;
    snackbarVisibility = true;
  }
</script>

<style>
  #main {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translateX(-50%) translateY(-50%);
    height: calc(100vh - 40%);
    width: calc(100vw - 40%);
    padding: 15px;

    background-color: white;
    border-radius: 6px;
    box-shadow: 0 0 5px white;

    text-align: left;
  }

  span {
    display: block;
    margin-top: 20px;
  }

  button {
    margin-top: 15px;
    margin-right: 15px;
    padding: 10px;
    float: right;

    color: white;
    background-color: #ff3e00;
    border: none;
    border-radius: 10px;
    cursor: pointer;
  }

  button:hover {
    box-shadow: 0 0 5px #ff3e00;
  }

  #heading {
    font-size: 24px;
    font-weight: bolder;
  }

  #difficulty {
    position: absolute;
    right: 16px;
    top: 16px;
    height: 25px;
    width: 80px;
    padding: 5px;

    background: rgb(97, 225, 230);
    color: white;
    text-align: center;
    border-radius: 16px;
  }

  #category {
    font-size: 12px;
    font-weight: normal;
  }

  #button-bar {
    position: absolute;
    bottom: 16px;
    right: 0;
  }

  #choice {
    margin-top: 16px;
    padding: 8px;

    border: 1px solid #4e5656;
    border-radius: 8px;
  }

  #choice:hover {
    cursor: pointer;
    background: green;
    border: 1px solid green;
    color: white;
  }

  #snackbar {
    position: absolute;
    left: 16px;
    bottom: 16px;
  }

  @media screen and (max-width: 960px) {
    #main {
      width: calc(100vw - 15%);
    }
    #difficulty {
      top: -16px;
    }
  }
</style>

<div id="main">
  <span id="heading"
    >Question {questionNo + 1}
    <i id="category">(Category - {category})</i></span
  >
  <span>{question}</span>
  <div id="difficulty">{difficulty}</div>

  {#if answerChoices} {#each answerChoices as choice}
  <div id="choice" on:click="{(e) => handleAnswerChoice(e)}">
    <i>{choice}</i>
  </div>
  {/each} {/if}

  <div id="button-bar">
    {#if !(questionNo > 10)}
    <button value="Next" on:click="{() => handleClick('f')}">Next</button>
    {/if} {#if questionNo > 0}
    <button value="Back" on:click="{() => handleClick('b')}">
      Previous
    </button>
    {/if}
  </div>

  {#if snackbarVisibility}
  <div id="snackbar">
    <Snackbar message="{correct}"></Snackbar>
  </div>
  {/if}
</div>

И вот у нас есть приложение, полностью написанное на Svelte. Используйте npm run dev, чтобы увидеть свое приложение в действии. Это действительно небольшое приложение, которое демонстрирует, что мы можем делать с помощью Svelte, и для меня это могло бы революционизировать то, как мы проектируем для Интернета, и я очень рад тому, что нас ждет впереди.

Основная цель этой статьи состояла в том, чтобы дать вам обзор Svelte и того, насколько это круто. Я надеюсь, что теперь вы чувствуете себя более комфортно при использовании Svelte.

Мысли 💭

Пожалуйста, поделитесь со мной своими мыслями о Svelte в разделе обсуждения ниже. Кроме того, не стесняйтесь задавать какие-либо вопросы, если вы где-то застряли в приложении, хотите узнать о нем больше или не уверены в какой-либо части.

Спасибо за чтение!

Как всегда, свяжись со мной в Твиттере и Инстаграм.

До следующего раза, спокойствия и счастливого кодирования !!!

Ваше здоровье.

Первоначально опубликовано на https://dev.to 24 ноября 2019 г.