Переход от jQuery к Vue

18 ноября 2019 | jQuery JavaScript Vue

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

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

Что мы рассмотрим:

  1. Поиск элемента в DOM
  2. Изменение DOM-элементов (абзац, класс кнопки и т.п.)
  3. Чтение и установка значений формы
  4. Проверка формы
  5. Работа с Ajax
  6. Обработка событий (например, нажатие на кнопку)
  7. Изменение стилей элемента

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

Где работает Vue?

Когда мы помещаем jQuery на страницу, мы можем выполнить любую задачу в любом порядке. У Vue есть одно существенное отличие. При запуске проекта мы начинаем с определения “области” в DOM, на которой хотим сосредоточиться. Рассмотрим простой прототип страницы:

<body>

  <header>
    Fancy header stuff here
  </header>

  <div id="sidebar">
    Some sidebar doohicky here
  </div>

  <main>
    <p>
      Main site content here, super important stuff...
    </p>
    <div id="loginForm">
      A login form of course
    </div>
  </main>

</body>

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

$(document).ready(function() {

  $('header') // something...

  $('#sidebar') // something...

  $('#loginForm') // something... 

});

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

new Vue({
  el: '#loginForm',
  // Code here...
});

Это означает, что сначала мы заканчиваем работу с формой. А потом, если клиент захочет что-то добавить в сайдбар - будем отдельно работать с сайдбаром.

new Vue({
  el: '#loginForm',
  // Code here...
});
new Vue({
  el:'#sideBar',
  // Code here...
});

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

Поиск элементов в DOM

Рассмотрим сразу пример. У нас есть кнопка, при клике на которую мы что-то делаем. Вот сокращенный пример того, как это может выглядеть:

<button id="myButton">Click Me!</button>
<!-- More stuff... -->
<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 немного более многословно, но обратите внимание, что разметка имеет прямую связь между действием («кликом») и вызываемой функцией. Код Vue не привязан к DOM (за пределами той el части, где мы определяем, где он должен работать). Это была одна из тех вещей, из-за которой я перешел на Vue - легче сказать, что происходит в коде. Кроме того, мне не нужно сильно беспокоиться о значении идентификатора и селекторах. Если я изменю класс или идентификатор кнопки, мне не нужно возвращаться к своему коду и беспокоиться об обновлении селекторов.

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

<button id="myButton">Click Me!</button>
<span id="result"></span>

<!-- More stuff... -->

<script>
$(document).ready(function() {

  $('#myButton').click(function() {
    $('#result').text('You clicked me, thanks!');
  });

});
</script>

И тоже самое на Vue:

<div id="app">
  <button v-on:click="doSomething">Click Me!</button>
  <!-- On click, change text in this span -->
  <span>{{resultText}}</span>
</div>

<script>
const app = new Vue({
  el: '#app',
  data: {
    resultText: ''
  },
  methods: {
    doSomething: function() {
      this.resultText = 'You clicked me, thanks!';
    }
  }
});
</script>

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

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

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

Работа с формами, вероятно, одна из самых распространенных и полезных вещей, которую мы можем сделать с помощью JavaScript. Формы всегда были критически важны для Интернета, и, вероятно, они останутся такими же в течение довольно долгого времени. Давайте рассмотрим простой пример 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() . В итоге мы получаем четыре элемента из 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* создает двустороннюю привязку данных между значениями элементом DOM и данными JavaScript. Переменные data будут автоматически связаны с input. Измените данные, и форма обновится. Измените форму, и данные обновятся. Флаг .number - это флаг, который обрабатывает строковые значения полей формы как числа. Если мы оставим это и сделаем сумму как есть, мы увидим сложение строк, а не математическую операцию.

Еще одна «хитрость» - это @click.prevent. Это эквивалент event.preventDefault().

Последнее - это добавление метода doSum, привязанного к этой кнопке. Обратите внимание, что он просто работает с переменными данных (которые 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 и, возможно, будете рады, что ее избежали.) Простой метод $.get(...) в jQuery в большинстве случае, а когда он был нужен для чего-то более сложного, на помощь приходил метод $.ajax().

Итак, что Vue делает для вас, чтобы облегчить Ajax? Ничего!

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

Первое, что нужно рассмотреть, это Axios - библиотека на базе Promise, которая очень популярна среди сообщества 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 и позволяет нам указывать заголовки, а также множество других опций.

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

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

  1. Поддержка фильтрации по имени и категории продукта
  2. Проверка формы. Мы должны предоставить поисковый термин или категорию
  3. Пока API работает, показывать сообщение пользователю и отключить кнопку отправки
  4. Когда закончим, обработать отчет о том, что продукты не были найдены, или показать товары

Давайте начнем с версии 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>

Здесь форма с нашими двумя фильтрами и двумя блоками с результатами. Один используется как временный статус при поиске или сообщении об ошибках, а другой используется для отображения результатов. Теперь JavaScript:

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, с которыми мы хотим работать - полей формы, кнопки и элементов div. Основная логика находится в обработчике нажатия кнопки. Мы делаем проверку, и если все в порядке, делаем запрос POST к API. Когда запрос обработан, мы либо отображаем результаты, либо показываем сообщение, если ничего не найдено.

Вы можете ознакомиться с полной версией этой демонстрации, используя CodePen ниже.

Теперь давайте рассмотрим версию 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>

Какая в итоге разница:

  1. Обернули макет в div, который можно использовать, чтобы сказать Vue, где работать.
  2. Использовали v-model для полей формы, чтобы облегчить работу с данными.
  3. Использовали @click.prevent для обработки основной операции поиска.
  4. Использовали :disabled для отключения кнопки, если идет запрос к API
  5. Отображение статуса немного отличается от предыдущих примеров. В jQuery есть разные методы для вывода текста и HTML. Vue требует атрибута v-html, если нам нужно вывести HTML-код. Если сделать просто {{status}} - теги будут экранированы.
  6. Наконец, используется 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>';
      });
      
    }
  }
});

Смерть JQuery! Да здравствует Vue!

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

Оригинал статьи

Поделиться в социальных сетях