Переход с jQuery на Vue

«Making the Move from jQuery to Vue»

https://www.smashingmagazine.com/2018/02/jquery-vue-javascript/

Как тот, кто использовал jQuery многие годы и недавно стал переходить на Vue, я подумал, что было бы интересно обсудить процесс миграции с одного на другой.

Некоторые люди могут не знать, что вы можете включить Vue в свой проект так же, как вы включили бы jQuery, без необходимости сборки. Vue гибок в том смысле, что мы можем использовать его непосредственно в HTML.

Итак, если ваша текущая структура страницы выглядит следующим образом:

<main>

  <div class=»thing»>

     <p>Some content here</p>

  </div>

</main>

<script src=»https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js»></script>

<script>

  //some jquery code here

</script>

Вы можете буквально изменить тег script здесь и при этом использовать HTML и JS в тандеме, как вы делали это раньше, с рефакторингом лишь нескольких маленьких кусочков кода. Вам не нужно переписывать HTML в JavaScript, вам не нужно использовать веб-пакет и вам не нужно настраивать гигантскую систему:

<main>

  <div class=»thing»>

     <p>Some content here</p>

  </div>

</main>

<script src=»https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js»></script>

<script>

  //some vue code here

</script>

Вы можете заменить теги и оставить разметку как есть. Самое приятное то, что вы можете подумать, что код станет более сложным, но, прочитав эту статью и увидев примеры, вы обнаружите, что Vue чрезвычайно прост, удобочитаемый, прост в обслуживании и адаптации. С точки зрения размера, они довольно сравнимы — использовать их, как и в минимизированной CDN, версия Vue 2.5.3 — 86 КБ . JQuery 3.2.1 составляет 87 КБ .

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

Это руководство в большей степени для людей с многолетним опытом использования jQuery, желающих узнать, как можно сделать те же вещи с помощью Vue. Имея это ввиду, я собираюсь сфокусироваться на том, что я считаю основными кейсами использования jQuery. Я не буду охватывать все возможные фичи, а вместо этого возьму подход «что я чаще всего делал с помощью jQuery», который может быть более узнаваемым для людей собирающихся изучить Vue. (Замечу так же, что-то как я пишу свои примеры — это просто один из способов выполнения задачи. jQuery и Vue предоставляют несколько способов достижения одной и той же цели, и это здорово!)

Имея это ввиду, давайте рассмотрим некоторые высокоуровневые вещи, которые мы можем делать при помощи jQuery:

  • Поиск чего-либо в DOM (и сделать что-либо с ним позже)
  • Изменение чего-либо в DOM (например текст параграфа или класс кнопки)
  • Чтение и изменение значений формы
  • Валидация формы (что на самом деле является комбинацией пунктов выше)
  • Ajax запросы и обработка результатов
  • Обработка событий (например, по клику на кнопку делать что-то)
  • Измерение или изменение стилей элемента

Конечно, в jQuery существует больше возможностей, но это наиболее общие юзкейсы. Также заметьте, что в списке выше много пересекающихся вещей. Итак, должны ли мы начать с простого сравнения по каждому пункту? Нет, не так быстро. Давайте начнем с рассмотрения основных отличий во Vue приложении.

Инициализация Vue

Когда мы подключаем jQuery на страницу, мы обычно добавляем швейцарский нож в код JavaScript, чтобы покрывать типичные задачи веб разработки. Мы можем покрывать любые юзеркейсы в любом порядке по своему усмотрению. Например, сегодня клиент может попросить валидацию формы, затем через месяц или около того захотеть добавить ajax поиск в шапке сайта.

Vue имеет одно существенное отличие в данном случае. При запуске проекта с Vue, мы начинаем с определения места в DOM дереве, на котором мы хотим сфокусироваться. Итак, давайте рассмотрим простой прототип веб страницы:

<body>

  <header>

    Fancy header stuff here

  </header>

  <div id=»sidebar»>

    Здесь некий сайдбар

  </div>

  <main>

    <p>

      Здесь главный контент…

    </p>

    <div id=»loginForm»>

      И конечно форма логина

    </div>

  </main>

</body>

В типичном jQuery приложении, мы можем написать код, работающий с хедером, сайдбаром и формой логина или чем-либо еще:

$(document).ready(function() {

  $(‘header’) //…

  $(‘#sidebar’) //…

  $(‘#loginForm’) //…

});

Во Vue приложении мы сперва определяем с чем мы работаем. Представьте, что наш клиент попросил сперва добавить валидацию на елемент loginForm. Наш Vue код будет выглядеть следующим образом:

new Vue({

  el: ‘#loginForm’,

  // Тут код…

});

Если позже клиент решит что-то добавить в сайдбар, мы просто добавляем второе Vue приложение:

new Vue({

  el:’#loginForm’,

  // Тут код…

});

new Vue({

  el:’#sideBar’,

  // Тут код…

});

Это плохо? Абсолютно нет. Мы сразу же получаем преимущество инкапсуляции. Если мы случайно используем переменную с общим именем (мы все это делали), то можем не беспокоиться о конфликтах с другими частями нашего кода. Позже, когда клиент добавит новые требования, наличие наших уникальных наборов Vue, разделенных таким образом, дает нам больше спокойствия, что код не будет конфликтовать друг с другом.

Поиск чего-либо в DOM

Еще один аспект, который вы найдете интересным или страшным — это то, как найти что-либо в DOM. Это немного расплывчато, но давайте рассмотрим пример. У нас есть кнопка, и по клику на нее мы что-то делаем. Ниже сокращенный пример того, как это может выглядеть:

<button id=»myButton»>Click Me!</button>

<!— TODO… —>

<script>

$(document).ready(function() {

  $(‘#myButton’).click(function() {

    alert(1);

  });

});

</script>

Теперь давайте сравним с тем, как это можно сделать на Vue:

<div id=»app»>

  <button v-on:click=»doSomething»>Click Me!</button>

</div>

<script>

const app = new Vue({

  el:’#app’,

  methods: {

    doSomething: function() {

      alert(1);

    }

  }

});

</script>

Vue приложение немного более многословно, но обратите внимание как разметка имеет прямую связь с действием («click») и функцией, которая будет вызвана. Vue код не имеет связи с DOM (вне части el, где мы определяем его место работы). Это было одной из вещей которую мне смог предложить Vue, потому что так проще описать то, что происходит. Так же мне не нужно было беспокоиться о значении ID и селекторов. Если я изменю класс или ID кнопки, мне не нужно возвращаться в мой код и беспокоиться об обновлении селекторов.

Давайте рассмотрим другой пример: поиск и изменение текста в DOM. Представьте кнопку по клику на которою меняется текст в другой части DOM.

<button id=»myButton»>Click Me!</button>

<span id=»result»></span>

<!— TODO… —>

<script>

$(document).ready(function() {

  $(‘#myButton’).click(function() {

    $(‘#result’).text(‘You clicked me, thanks!’);

  });

});

</script>

Я добавил новый span и теперь, когда кнопка нажата, мы используем другой селектор, чтобы найти его и используем метод jQuery для изменения текста внутри. Теперь рассмотрим версию на Vue:

<div id=»app»>

  <button v-on:click=»doSomething»>Нажми на меня!</button>

  <!— По клику изменяем текст в span —>

  <span>{{resultText}}</span>

</div>

<script>

const app = new Vue({

  el: ‘#app’,

  data: {

    resultText: »

  },

  methods: {

    doSomething: function() {

      this.resultText = ‘Вы нажали на меня, спасибо!’;

    }

  }

});

</script>

В данном примере мы используем язык шаблонов Vue, чтобы определить, что мы хотим отрендерить переменную внутри span, которая является resultText в данном случае. Теперь, когда кнопка нажата, мы изменяем значение и текст внутри span меняется автоматически.

Vue поддерживает сокращение для v-on атрибута, так кнопка в примере может быть переписана с @click=»doSomething».

Чтение и запись значений формы

Работая с формами вероятно одна из наиболее распространенных и полезных вещей, которые мы делаем с помощью JavaScript. Даже до JavaScript, большая часть моей ранней «веб разработки» заключалась в написании Perl скриптов для обработки представлений форм. Как главный способ принятия пользовательского ввода, формы всегда были критически важны для веба, и это, вероятно, так и останется в течение довольно длительного времени. Давайте рассмотрим простой пример на jQuery с чтением нескольких полей формы и установки других:

<form>

  <input type=»number» id=»first»> +

  <input type=»number» id=»second»> =

  <input type=»number» id=»sum»>

  <button id=»sumButton»>Sum</button>

</form>

<script>

$(document).ready(function() {

  let $first = $(‘#first’);

  let $second = $(‘#second’);

  let $sum = $(‘#sum’);

  let $button = $(‘#sumButton’);

  $button.on(‘click’, function(e) {

    e.preventDefault();

    let total = parseInt($first.val(),10) + parseInt($second.val(),10);

    $sum.val(total);

  });

});

</script>

Данный код показывает как jQuery может читать и изменять значения с помощью метода val(). В итоге мы получаем 4 элемента из DOM дерева (все три поля формы и кнопку) и используем простую математику чтобы получить результат.

Теперь давайте рассмотрим версию на Vue:

<form id=»myForm»>

  <input type=»number» v-model.number=»first»> +

  <input type=»number» v-model.number=»second»> =

  <input type=»number» v-model=»sum»>

  <button @click.prevent=»doSum»>Sum</button>

</form>

<script>

new Vue({

  el: ‘#myForm’,

  data: {

    first: 0,

    second: 0,

    sum: 0

  },

  methods: {

    doSum: function() {

      this.sum = this.first + this.second;

    }

  }

})

</script>

Данный пример представляет некоторые интересные сокращения Vue. Во-первых, v-model это то, как Vue создает двухсторонний дата биндинг между значениями в DOM и JavaScript. Блок переменных data будет автоматически синхронизирован с полями формы. Изменение в data повлечет изменение в форме и наоборот. Флаг .number обрабатывает стоковые значения полей формы как числа. Если мы уберем это флаг и оставим сложение как есть, то мы получим конкатенацию строк, а не арифметику. Я работаю с JavaScript почти столетие и все равно лажаю.

Еще одна полезна фишка это @click.prevent. Сперва, @click определяет обработчик клика на кнопке, затем .prevent блокирует дефолтное поведение браузера по отправке формы (аналогично event.preventDefault()).

Финальная часть — это добавление метода doSum, которые связан с кнопкой. Заметим, что это просто работает с data переменными (которые Vue делает доступными в this).

Хотя в основном это мое личное мнение, мне действительно нравится отсутствие выборки селекторов в скрипте, когда мы пишем на Vue, и как в HTML становится ясно, что мы делаем.

В итоге, мы можем даже полностью избавится от кнопки:

<form id=»myForm»>

  <input type=»number» v-model.number=»first»> +

  <input type=»number» v-model.number=»second»> =

  <input type=»number» v-model=»sum»>

</form>

<script>

new Vue({

  el: ‘#myForm’,

  data: {

    first: 0,

    second: 0

  },

  computed: {

    sum: function() {

      return this.first + this.second;

    }

  }

})

</script>

Одна из наикрутейших фич Vue — это вычисляемые свойства. Они являются виртуальными значениями, которые распознают, когда их полученные значения изменены. В коде выше, как только любое из двух полей формы изменится, сумма будет обновлена. Это так же работает вне формы. Мы можем отрендерить сумму так:

The total is {{sum}}.

Работа с Ajax

Похвально то, насколько просто в jQuery сделана работа с Ajax. Фактически, я могу сказать, что я сделал Ajax запрос традиционным способом, наверное, всего один раз. (Если вам любопытно, вы можете посмотреть спецификацию XMLHttpRequest и, вероятно, будете счастливы избавить себя от этого.) Простой метод jQuery $.get(…) работает в большинстве случаев, и когда необходимо более сложное решение, $.ajax() делает это так же легко. Еще одна вещь, которую jQuery сделал хорошо — это то, как он обрабатывает JSONP запросы. Хотя теперь это в основном не нужно с появлением CORS, JSONP был способом обработки запросов к API на разных доменах.

Итак, что же Vue делает для упрощения Ajax запросов? Ничего!

Звучит страшно, но на самом деле это не так. Существует множество вариантов для работы с  HTTP запросами, и Vue выбрал более агностический путь, позволив нам, разработчикам, решать как мы хотим управлять этим. Так что да, это означает немного больше работы, но у нас есть несколько отличных вариантов.

Сперва рассмотрим Axios. Это библиотека основанная на промисах, которая очень популярна в среде Vue сообщества. Это простой пример (взятый из их README файла):

axios.get(‘/user?ID=12345’)

  .then(function (response) {

    // handle success

    console.log(response);

  })

  .catch(function (error) {

    // handle error

    console.log(error);

  })

  .then(function () {

    // always executed

  });

Axios конечно же поддерживает POST запросы и позволяет нам определять заголовки в числе многих других опций.

Пока Axios очень популярен среди Vue разработчиков, это не является чем-то что действительно зацепило меня. (По крайней мере пока.) Вместо этого я был гораздо большим поклонником Fetch. Fetch не является внешней библиотекой, это веб стандарт обработки HTTP запросов. Fetch имеет очень хорошую поддержку примерно в 90% браузеров, тем не менее это не означает что его абсолютно безопасно использовать, но мы всегда можем использовать полифил.

Хотя это полностью выходит за рамки того, что мы здесь обсуждаем, Кингсли Сайлас написал превосходный гайд по использованию Axios и Fetch с React.

Так же как и Axios, Fetch основан на промисах и имеет доступный API:

fetch(‘http://example.com/movies.json‘)

  .then(function(response) {

    return response.json();

  })

  .then(function(myJson) {

    console.log(JSON.stringify(myJson));

  });

Axios и Fetch покрывают все типы HTTP запросов, так что любой из них будет соответствовать любому количеству потребностей. Давайте рассмотрим простое сравнение. Ниже простое демо на jQuery, использующее Star Wars API.

<h1>Star Wars Films</h1>

<ul id=»films»>

</ul>

<script>

$(document).ready(function() {

  $.get(‘https://swapi.com/api/films‘, function(res) {

    let list = »;

    res.results.forEach(function(r) {

      list += `<li>${r.title}</li>`;

    });

    $(‘#films’).html(list);

  });

});

</script>

В примере выше я использую $.get , чтобы дернуть API и вернуть список фильмов. Затем я генерирую список заголовков тегами li и вставляю все в блок ul.

Теперь давайте рассмотрим этот пример с использованием Vue:

<div id=»app»>

  <h1>Star Wars Films</h1>

  <ul>

    <li v-for=»film in films»>{{film.title}}</li>

  </ul> 

</div>

<script>

const app = new Vue({

  el: ‘#app’,

  data: {

    films: []

  },

  created() {

    fetch(‘https://swapi.com/api/films‘)

    .then(res => res.json())

    .then(res => {

      this.films = res.results; 

    });

  }

})

</script>

Вероятно, лучшая часть этого примера — это использование директивы v-for в шаблоне. Обратите внимание, что Vue не связан с разметкой (ну по крайней мере JavaScript). Данные получены из API. Они присваиваются переменной. Разметка отображает эти данные. Я всегда ненавидел наличие HTML в моем JavaScript, и, хотя для этого существуют решения с jQuery, обработка во Vue делает это более натурально.

Полный (немного тривиальный) пример

Давайте рассмотрим более реальный пример. Наш клиент попросил нас сделать некий интерфейс для Ajax поиска c использованием API продуктов. Список особенностей включает:

  • Поддержку фильтрации по имени и категории продукта
  • Валидацию формы, так что мы можем подставить поисковый запрос или категорию
  • Пока выполняется запрос к API, показывать сообщение пользователю и деактивировать кнопку отправки
  • Когда запрос выполнен, обработать отчет о том, что продукты не были найдены или показать список совпадений

Давайте начнем с jQuery версии. Сперва HTML:

<form>

  <p>

    <label for=»search»>Search</label>

    <input type=»search» id=»search»>

  </p>

  <p>

    <label for=»category»>Category</label>

    <select id=»category»>

      <option></option>

      <option>Food</option>

      <option>Games</option>

    </select>

  </p>

  <button id=»searchBtn»>Search</button>

</form>

<div id=»status»></div>

<div id=»results»></div>

Есть форма с двумя фильтрами и двумя div. Один из них используется как временный статус, когда идет поиск или для отчета об ошибке, и другой для рендеринга результата. Теперь давайте посмотрим на код.

const productAPI = ‘https://wt-c2bde7d7dfc8623f121b0eb5a7102930-0.sandbox.auth0-extend.com/productSearch‘;

$(document).ready(() => {

  let $search = $(‘#search’);

  let $category = $(‘#category’);

  let $searchBtn = $(‘#searchBtn’);

  let $status = $(‘#status’);

  let $results = $(‘#results’);

  $searchBtn.on(‘click’, e => {

    e.preventDefault();

    // First clear previous stuff

    $status.html(»);

    $results.html(»);

    // OK, now validate form

    let term = $search.val();

    let category = $category.val();

    if(term === » && category === ») {

      $status.html(‘You must enter a term or select a category.’);

      return false;

    }

    $searchBtn.attr(‘disabled’,’disabled’);

    $status.html(‘Searching — please stand by…’);

    $.post(productAPI, { name:term, category:category }, body => {

      $searchBtn.removeAttr(‘disabled’);

      $status.html(»);

      if(body.results.length === 0) {

        $results.html(‘<p>Sorry, no results!</p>’);

        return;

      }

      let result = ‘<ul>’;

      body.results.forEach(r => {

        result += `<li>${r.name}</li>`

      });

      result += ‘</ul>’;

      $results.html(result);

    });

  });

});

Код начинается с установки переменных для каждого DOM элемента, с которым мы хотим работать — поля формы, кнопки и дивы. Ядро логики связано с обработкой клика по кнопке. Мы валидируем данные, и, если все OK, отправляем POST запрос к API. Когда получен результат, мы либо отображаем результат, либо показываем сообщение, что ничего не найдено.

Теперь давайте рассмотрим Vue версию. И вновь начнем с разметки:

<div id=»app»>

  <form>

    <p>

      <label for=»search»>Search</label>

      <input type=»search» v-model=»search»>

    </p>

    <p>

      <label for=»category»>Category</label>

      <select v-model=»category»>

        <option></option>

        <option>Food</option>

        <option>Games</option>

      </select>

    </p>

    <button @click.prevent=»searchProducts» :disabled=»searchBtnDisabled»>Search</button>

  </form>

    <div v-html=»status»></div>

    <ul v-if=»results»>

      <li v-for=»result in results»>{{result.name}}</li>

    </ul>

</div>

Изменения выше включают в себя:

  • Обертка разметки в div, который сообщает Vue где он будет работать.
  • Использование v-model для полей формы, чтобы сделать проще работу с данными.
  • Использование @click.prevent, чтобы вызвать обработку главной поисковой операции.
  • Использование :disabled для связи того, будет ли кнопка отключена или нет со значением во Vue приложении (мы увидим это в действии через мгновение).
  • Значение статуса немного другое, по сравнению с предыдущими примерами. В то время как jQuery имеет особый метод для установки текста в DOM элемент и другой метод для установки HTML, Vue требует использования v-html директивы, когда мы назначаем HTML в качестве значения, которое собираемся отрендерить. Если мы попытаемся отренедрить HTML в {{status}}, теги будут опущены.
  • И наконец, используем v-if для условного рендеринга списка результатов с помощью директивы v-for.

Теперь давайте посмотрим на код.

const productAPI = ‘https://wt-c2bde7d7dfc8623f121b0eb5a7102930-0.sandbox.auth0-extend.com/productSearch‘;

const app = new Vue({

  el: ‘#app’,

  data: {

    search: »,

    category: »,

    status: »,

    results: null,

    searchBtnDisabled: false

  },

  methods: {

    searchProducts:function() {

      this.results = null;

      this.status = »;

      if(this.search === » && this.category === ») {

        this.status = ‘You must enter a term or select a category.’;

        return;

      }

      this.searchBtnDisabled = true;

      this.status = ‘Searching — please stand by…’;

      fetch(productAPI, {

        method: ‘POST’,

        headers: {

          ‘Content-Type’:’application/json’

        },

        body: JSON.stringify({name:this.search,category:this.category})

      }).then(res => res.json())

      .then(res => {

        this.status = »;

        this.searchBtnDisabled = false;

        this.results = res.results;

        if(this.results.length === 0) this.status = ‘<p>Sorry, no results!</p>’;

      });

    }

  }

});

Первый блок data устанавливает необходимые нам поля, некоторые из которых предназначены для результата, статусных сообщений и другого в этом роде. Метод searchProducts по большей части обрабатывает то же самое что и в jQuery версии, за исключением гораздо меньшего кода, напрямую связанного с DOM. Например, имея массив данных, сам код не беспокоится о рендеринге. Он просто меняет значение переменной и шаблон вызывает рендеринг этих данных. В данном случае, по сравнению с  jQuery кодом,  JavaScript больше занимается логикой, и это разделение ответственности гораздо более приятно.

Однако, я могу сказать, что Vue ощущается как «следующий шаг» для людей, которые обычно работают с jQuery. Vue поддерживает сложные приложения и имеет великолепный CLI для скаффолдинга и сборки проектов. Но для более простых задач, Vue работает как превосходная замена jQuery, которую я выбрал в качестве своего инструмента разработки!

Захват Входных Данных Пользователя

Действительно распространенный вариант использования JavaScript на сайте — это захват пользовательского ввода из формы, поэтому давайте начнем с него. На самом деле мы пока не будем включать полную форму в интересах простоты и ясности, но мы будем работать над этим до конца.

Чтобы собирать информацию по типу пользователя, вот как мы будем это делать в jQuery и Vue — бок о бок:

<div id=»app»>

  <label for=»thing»>Name:</label>

  <input id=»thing» type=»text» />

  <p class=»formname»></p>

</div>

// this is an alias to $(document).ready(function() {

$(function() {

  //keypress wouldn’t include delete key, keyup does. We also query the div id app and find the other elements so that we can reduce lookups

  $(‘#app’).keyup(function(e) {

    var formname = $(this).find(‘.formname’);

    //store in a variable to reduce repetition

    var n_input = $(this).find(‘#thing’).val();

    formname.empty();

    formname.append(n_input);

  });

});

<div id=»app»>

  <label for=»name»>Name:</label>

  <input id=»name» type=»text» v-model=»name» /> <!—v-model is doing the magic here—>

  <p>{{ name }}</p>

</div>

//this is a vue instance

new Vue({

  //this targets the div id app

  el: ‘#app’,

  data: {

    name: » //this stores data values for ‘name’

  }

})

Я использую этот пример, потому что он раскрывает некоторые сильные стороны Vue. Vue реагирует, что делает его особенно способным реагировать на изменения. Вы можете видеть, как по мере того, как мы обновляем то, что мы печатаем, оно мгновенно меняется — без задержки.

Вы также можете видеть, что в версии jQuery DOM находится под контролем — мы извлекаем вещи из DOM, слушаем его и отвечаем на него. Это связывает нас с тем, как DOM настроен в настоящее время, и заставляет задуматься о том, как его пройти. Если бы структура элементов HTML изменилась, нам пришлось бы адаптировать наш код, чтобы соответствовать этим изменениям.

В версии Vue мы сохраняем состояние — мы отслеживаем одно свойство, которое мы хотим обновить и изменить, и отслеживаем элемент, который мы хотим изменить, с помощью вещи, называемой директивой. Это означает, что он прикреплен непосредственно к HTML-элементу, который нам нужен. Структура DOM может измениться, HTML может двигаться, и ничего из этого не повлияет на нашу производительность или захват этих событий. В нашем случае мы используем этот атрибут v-модели на входе для подключения к данным, которые мы храним в JavaScript.

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

Хранение Пользовательского Ввода Для Одного События

Интересная вещь в том, как работает Vue, заключается в том, что он не связан с необходимостью думать о конкретных событиях DOM при хранении и извлечении данных. По сути, у нас уже есть представление о том, что мы хотим запечатлеть; мы придаем ему форму, выбирая событие, с помощью которого можно его изменить. Напротив, jQuery тесно связан с тем, что делает DOM, и опирается на эти события DOM для создания переменных, которые он хранит, которые могут быть размещены, где угодно, а не одной согласованной группой (в данных) для извлечения. Мы можем видеть это в обновленной версии последнего примера, где информация собирается нажатием клавиши ввода:

<div id=»app»>

  <label for=»thing»>Name:</label>

  <input id=»thing» type=»text» />

  <p class=»formname»></p>

</div>

// this is an alias to $(document).ready(function() {

$(function() {

  //We query the div id app and find the other elements so that we can reduce lookups

  $(‘#app’).change(function(e) {

    var n_input = $(this).find(‘#thing’).val();

    $(this).find(‘.formname’).append(n_input);

  });

});

<div id=»app»>

  <label for=»name»>Name:</label>

  <input id=»name» type=»text» v-model.lazy=»name» />

  <p>{{ name }}</p>

</div>

new Vue({

  el: ‘#app’,

  data: {

    name: »

  }

});

В этой версии jQuery несколько упрощен, потому что нам не нужно захватывать вещи при каждом нажатии клавиши, но мы все еще выискиваем вещи из DOM и реагируем шаг за шагом на эти изменения. Наш код в jQuery всегда будет выглядеть примерно так:

«Иди возьми этот элемент, посмотри, что он делает, держись за эти изменения, сделай что-нибудь с этими изменениями».

Для сравнения: в Vue мы контролируем то, что меняется, и DOM реагирует на эти изменения на основе наших команд. Мы прикрепляем его непосредственно к тому, что хотим обновить. В нашем случае, у нас есть небольшая абстракция называется модификатор: v-model.lazy. Теперь Vue знает, что не следует сохранять это, пока не произойдет событие change. Довольно аккуратно!

Переключение Классов

Следующая вещь, которую мы рассмотрим, это переключение классов CSS, потому что, как мне всем всемогущий, постоянно наблюдающий Googly, это самая распространенная функциональность jQuery.

<div id=»app»>

  <button aria-pressed=»false»>Toggle me</button>

  <p class=»toggle»>Sometimes I need to be styled differently</p>

</div>

.red {

  color: red;

}

JS

$(function() {

  $(‘button’).click(function(e) {

    $(‘.toggle’).toggleClass(‘red’);

    $(this).attr(‘aria-pressed’, ($(this).attr(‘aria-pressed’) == «false» ? true : false));

  });

});

<div id=»app»>

  <button @click=»active = !active» :aria-pressed=»active ? ‘true’ : ‘false'»>Toggle me</button>

  <p :class=»{ red: active }»>Sometimes I need to be styled differently</p>

</div>

.red {

  color: red;

JS

new Vue({

  el: ‘#app’,

  data: {

    active: false

  }

})

Опять же, здесь мы видим, что в версии jQuery мы сохраняем состояние в DOM. Элемент имеет класс, и jQuery принимает решение на основе присутствия класса, который он проверяет путем проверки связи с DOM. В версии Vue мы сохраняем условие и стилизуем его в соответствии с этим состоянием. Мы не просим DOM об этой информации, мы держим ее сами.

Мы сохраняем active данные, кнопка переключает условие и .red изменяется в зависимости от этого условия. Даже состояния для доступности, aria-pressed устанавливаются намного быстрее, поскольку нам не нужно ничего устанавливать в скрипте в Vue, мы можем переключаться между состояниями, непосредственно встроенными в шаблон, на основе состояния ‘ active.’

Вы также заметите, что в последних нескольких примерах вы могли подумать, что для работы с Vue.js будет намного больше кода, чем для jQuery, но на самом деле они довольно сопоставимы.

Сокрытие и показ

Еще один распространенный случай использования jQuery — скрывать и показывать что-то. jQuery всегда делал действительно хорошую работу по упрощению этой задачи, поэтому давайте посмотрим, как она выглядит из стороны в сторону с Vue.

<div id=»app»>

  <button type=»button» id=»toggle» aria-expanded=»false»>

    Toggle Panel

  </button>

  <p class=»hello»>hello</p>

</div>

$(function() {

  $(‘#toggle’).on(‘click’, function() {

    $(‘.hello’).toggle();

    $(this).attr(‘aria-expanded’, ($(this).attr(‘aria-expanded’) == «false» ? true : false));

  });

});

<div id=»app»>

  <button @click=»show = !show» :aria-expanded=»show ? ‘true’ : ‘false'»>

    Toggle Panel

  </button>

  <p v-if=»show»>hello</p>

</div>

new Vue({

  el: ‘#app’,

  data: {

    show: true

  }

})

И jQuery, и Vue отлично справляются с этой задачей, выполняя простую задачу, но есть несколько причин, по которым я действительно работаю с Vue для чего-то вроде переключения. У Vue есть инструмент под названием Vue devtools. Это мало чем отличается от Chrome devtools, но, когда мы его используем, мы получаем некоторую специальную информацию о том, что происходит с Vue.

Как в jQuery, так и в версии Vue мы видим, что элемент скрывается и появляется. Но что, если что-то пойдет не так? Что если что-то в нашем коде не работает так, как мы ожидали? Чтобы начать отладку с помощью jQuery, мы, вероятно, добавили бы некоторые console.log или установили несколько точек останова, чтобы попытаться отследить, где что-то происходило с ошибками.

Теперь, с console.log не все в порядке, но с помощью разработчиков Vue мы можем фактически получить Vue (не смог устоять) о том, что Vue думает, что происходит. В этом gif ниже вы можете увидеть, как при переключении кнопки Vue devtools обновляет состояние true / false соответственно. Если бы DOM никогда не работал так, как мы ожидали, мы могли бы видеть данные в Vue в реальном времени. Это намного облегчает отладку; это на самом деле довольно замечательно.

Еще одна вещь, которая мне нравится в этом, это то, что v-if ее легко распространить на другие условия. Я могу решить использовать вещь, называемую v-show вместо, v-if если вещь, которую я переключаю, будет часто показывать и скрывать: v-if полностью размонтирует элемент, v-show просто переключая видимость этого. Это различие действительно важно, потому что гораздо удобнее переключать видимость в стиле, чем полностью отключать / монтировать узел DOM. Я могу показать или скрыть что-либо на основе множества условий, или даже наличия ввода пользователя или других условий. Это обычно, когда jQuery может немного запутаться, проверяя DOM в нескольких местах и ​​координируя их. Ниже приведен пример координирования показа чего-либо на основе присутствия пользовательского ввода:

<div id=»app»>

  <label for=»textarea»>What is your favorite kind of taco?</label>

  <textarea id=»textarea» v-model=»tacos»></textarea>

  <br>

  <button v-show=»tacos»>Let us know!</button>

</div>

new Vue({

  el: ‘#app’,

  data() {

    return {

      tacos: »

    }

  }

})

<div id=»app»>

  <label for=»textarea»>What is your favorite kind of taco?</label>

  <textarea id=»textarea»></textarea>

  <br>

  <button v-show=»tacos»>Let us know!</button>

</div>

$(function() {

  var button = $(‘.button’);

  var textarea = $(‘#textarea’);

  button.hide();

  textarea.keyup(function() {

    if (textarea.val().length > 0) {

      button.show();

    } else {

      button.hide();

    }

  })

});

В этом примере вы можете увидеть, как Vue удерживает состояние — мы реагируем на изменения очень естественно и с меньшим количеством кода. Как только вы привыкнете к стилю, его быстрее понять, потому что вам не нужно прослеживать логику построчно. Многие люди называют это различие « обязательным и декларативным».

Отправка Формы

Каноническим вариантом использования jQuery исторически была отправка формы с вызовом AJAX, поэтому мы должны взглянуть и на это. У Vue на самом деле нет такой встроенной вещи, как AJAX; В приложении Vue обычно используется что-то вроде Axios (библиотека JavaScript для выполнения HTTP-запросов), чтобы помочь с этой задачей.

Этот пример немного сложнее, чем остальные. Мы собираемся сделать несколько вещей здесь:

  1. Кнопка станет серой, прежде чем мы начнем печатать в нашей форме, затем она получит «активный» класс и станет синей;
  2. Когда мы отправим форму, мы не допустим загрузки страницы;
  3. Когда форма будет отправлена, мы покажем данные ответа на странице.

<div id=»app»>

  <form action=»/»>

    <div>

      <label for=»name»>Name:</label><br>

      <input id=»name» type=»text» name=»name» required/>

    </div>

    <div>

      <label for=»email»>Email:</label><br>

      <input id=»email» type=»email» name=»email»  required/>

    </div>

    <div>

      <label for=»caps»>HOW DO I TURN OFF CAPS LOCK:</label><br>

      <textarea id=»caps» name=»caps» required></textarea>

    </div>

    <button class=»submit» type=»submit»>Submit</button>

    <div>

      <h3>Response from server:</h3>

      <pre class=»response»></pre>

    </div>

  </form>

</div>

$(function() {

  var button = $(«button»);

  var name = $(«input[name=name]»);

  name.keyup(function() {

    if (name.val().length > 0) {

      button.addClass(‘active’);

    } else {

      button.removeClass(‘active’);

    }

  });

  $(«form»).submit(function(event) {

    event.preventDefault();

    //get the form data

    var formData = {

      name: $(«input[name=name]»).val(),

      email: $(«input[name=email]»).val(),

      caps: $(«input[name=caps]»).val()

    };

    // process the form

    $.ajax({

      type: «POST»,

      url: «//jsonplaceholder.typicode.com/posts»,

      data: formData,

      dataType: «json»,

      encode: true

    }).done(function(data) {

      $(«.response»)

        .empty()

        .append(JSON.stringify(data, null, 2));

    });

  });

});

Здесь мы увидим строки 2-10, посвященные обработке класса кнопки, аналогично тому, как мы делали это раньше. Мы передаем в форму параметр с именем event, а затем говорим, event.preventDefault() чтобы не перезагружать страницу. Затем мы собираем все данные формы из входных данных формы, обрабатываем форму и затем помещаем ответ в .done()вызов от запроса AJAX.

<div id=»app»>

  <form @submit.prevent=»submitForm»>

    <div>

      <label for=»name»>Name:</label><br>

      <input id=»name» type=»text» v-model=»name» required/>

    </div>

    <div>

      <label for=»email»>Email:</label><br>

      <input id=»email» type=»email» v-model=»email» required/>

    </div>

    <div>

      <label for=»caps»>HOW DO I TURN OFF CAPS LOCK:</label><br>

      <textarea id=»caps» v-model=»caps» required></textarea>

    </div>

    <button :class=»[name ? activeClass : »]» type=»submit»>Submit</button>

    <div>

      <h3>Response from server:</h3>

      <pre>{{ response }}</pre>

    </div>

  </form>

</div>

new Vue({

  el: ‘#app’,

  data() {

    return {

      name: »,

      email: »,

      caps: »,

      response: »,

      activeClass: ‘active’

    }

  },

  methods: {

    submitForm() {

      axios.post(‘//jsonplaceholder.typicode.com/posts’, {

        name: this.name,

        email: this.email,

        caps: this.caps

      }).then(response => {

        this.response = JSON.stringify(response, null, 2)

      })

    }

  }

})

В версии Vue мы решаем, какие поля нам нужно заполнить в форме, а затем присоединяем их к той v-модели, которую мы использовали ранее. Мы проверяем наличие имени, чтобы переключить класс. Вместо того, чтобы передавать события и писать event.preventDefault(), все, что нам нужно сделать, это написать @submit.prevent в нашем элементе формы, и это позаботится о нас. Чтобы отправить само сообщение, мы используем Axios, и мы будем хранить ответ в экземпляре Vue в ответ.

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

Заключение

Определенно можно использовать jQuery, если он вам подходит! Эта статья служит для того, чтобы показать, что Vue — также довольно хорошая абстракция для небольших сайтов, которые не требуют больших накладных расходов. Vue сопоставим по размеру, его легко рассуждать, и довольно просто переключить небольшие функциональные возможности на Vue, не переписывая HTML-код в JavaScript и не применяя систему сборки, если у вас нет пропускной способности. Все это заставляет задуматься.

Благодаря гибкости Vue этот код также легко перевести на этап сборки и структуры компонентов, если вы хотите со временем принять более сложную структуру. На самом деле очень интересно попробовать, поэтому, когда вы будете готовы сделать это, посмотрите vue-cli . Этот инструмент дает вам возможность создать целую сборку Vue и веб-пакета производственного уровня с помощью всего лишь нескольких команд терминала. Это позволяет вам работать с однофайловыми компонентами, где вы можете использовать HTML, CSS и Script совместно в одном файле, который составляет отдельные компоненты многократного использования. Вам не нужно настраивать сборку веб-пакета, если вы не хотите делать что-то особенное, поэтому вы экономите много времени на настройке. У них даже есть встроенная команда для подготовки всего к производственному развертыванию.

Приятная вещь о гибкости выбора любого из способов включения Vue в ваш проект означает, что вы не будете вынуждены менять свой стиль работы сразу, и вы даже можете постепенно вносить изменения с течением времени. Вот почему люди называют Vue прогрессивной структурой.

 

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.