Love Frontend
Статья опубликована: 10.04.2017

VueJS - Основы

Vue.js это небольшая, гибкая JavaScript библиотека, которая позволяет разработчикам довольно легко создавать интерактивные web приложения с помощью API, который так же прост и легок в освоении. У него есть некоторые сходства и некоторые различия с другими библиотеками/фрэймворками, такими как Angular, React, Ember, Polymer, и Riot и прочие. Однако Vue может похвастаться своей простотой, производительностью, гибкостью и своей меньшей самоуверенностью. Сайт Vue.js имеет более глубокое сравнение с другими библиотеками и фрэймворками, которое вы можете прочитать здесь, если вам это интересно.

Цель данного руководства дать вам общее представление некоторых основных концепций Vue с помощью реальных примеров. Следующие туториалы будут более продвинутыми и мы будем строить большое приложение с Vue.

Создание Vue экземпляра с помощью new Vue()

Давайте начнём с создания основной HTML страницы и импортирования Vue.js в неё. Вы можете установить Vue через NPM, Yarn, Bower, как отдельный файл или через CDN. Ради простоты, мы подключим Vue со ссылкой на библиотеку из официальной документации, прямо перед закрывающимся тегом body, вот так:


  <!DOCTYPE html>
  <html>
    <head>
      <title>VueJs Tutorial - Love Frontend</title>
    </head>
    <body>

    <script src="https://unpkg.com/vue"></script>
    </body>
  </html>

Заметка: когда вы разработаываете, убедитесь, что вы используете не минимизированную версию, это даст вам полезные и описательные ошибки (warnings), что позволит сохранить вам много времени.

Теперь мы можем создать div тег и новый экземпляр Vue, который привяжется к элементу. Когда вы создаёте новый экземпляр Vue используя Vue() конструктор (constructor), вам нужно обязательно указать точку прикрепления (элемент), о которой вы можете думать, как о границе или коробке для нашего Vue экземпляра - он будет знать только о вещах, задекларированных внутри этого элемента, и не будет знать ничего о элементах снаружи этого div'а.

Вы можете определить точку прикрепления для Vue экземпляра используя параметр el в конструкторе Vue(), который принимает строку с CSS селектором DOM элемента, в который вы хотели бы установить ваш Vue экземпляр, пример ниже:


<!DOCTYPE html>
<html>
  <head>
    <title>VueJs Tutorial - Love Frontend</title>
  </head>
  <body>

  <div id="vue-instance">
    <!-- Сюда будет рендерится ваш Vue экземпляр -->
  </div>

  <script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>

  <script>
    // наш VueJS instance привязывается к div элементу по его id
    var vm = new Vue({
      el: '#vue-instance'
    });
  </script>

  </body>
</html>

Как вы можете видеть выше, Vue экземпляр создан с помощью Vue() constructor и принимает в качестве опций объект, который определяет элемент, в который этот экземпляр Vue будет помещен. В нашем случае мы создаем новый Vue экземпляр и определяем элемент в который он будет установлен через CSS селектор: #vue-instance. Vue экземпляр также может рассматриваться как ViewModel в MVVM шаблоне проектирования. Следовательно имя переменной vm будет отлично подходить в нашем случае.

Сейчас у нас есть созданный Vue экземпляр, установленный в DOM элемент. Vue осведомлён обо всём необходимом в пределах этого div тега и мы можем начинать демонстрировать функции Vue.

2-way data binding (привязка данных) с v-model

Чтобы проиллюстрировать двухсторонню привязку данных в Vue.js, мы создадим простой HTML текстовый input с директивой v-model, которая будет использоваться для динамического обновления "greeting" свойств в объекте data. Вы можете думать о v-model директиве как о любом другом HTML аттрибуте. Это создаст двухсторонню привязку данных к элементам формы, таким как <input>, <textarea>, и <select>. Значение директивы v-model это данные, которые мы хотим обновлять при событиях в input. Для этого конкретного примера, мы привяжем <input> элемент к строке "greeting", которую мы создаем в объекте data как показано ниже:


<div id="vue-instance">
  Введите приветствие: <input type="text" v-model="greeting">
</div>

<script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>

<script>
  var vm = new Vue({
    el: '#vue-instance',
    data: {
      greeting: 'Hello VueJs!'
    }
  });
</script>

На данный момент, в любое время, когда пользователь введет что-нибудь в текстовое поле, строка "greeting" будет обновлена в объекте data автоматически и также если сама строка изменится, то текстовое поле также автоматически обновит своё содержимое. Эта постоянная синхронизация между элементами формы и лежащим в основе data объекте достигается благодаря аттрибуту v-model и это то место, где возникает понятие двухстороняя привязка данных (2-way data bindings).

Чтобы доказать двухсторонюю привязку между элементом <input> и лежащей в данных строкой "greeting" мы можем вывести data объект нашего экземпляра Vue на страницу используя специальное свойство $data заключенное в двойные фигурные скобки, что фактически скажет Vue заменить что-бы там не находилось между этими фигурными скобками {{}} свойством соответствующим объекту data.


<div id="vue-instance">
  Введите приветствие: <input type="text" v-model="greeting">
    <pre>{{ $data | json }}</pre>
</div>

<script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>

<script>

  var vm = new Vue({

    el: '#vue-instance',
    data: {

      greeting: 'Hello VueJs!'

    }

  });

</script>

Поэксперементируйте прямо тут

See the Pen Vuejs-basics#1 by kamil Ocean (@kamil-ocean) on CodePen.

Фрагмент " | json " в {{ $data | json }} это просто вспомогательный метод (фильтр) чтобы вывести отформатированный $data объект. Всё что по настоящему делает этот фильтр, это вызов JSON.stringify().

Похожим способом вы можете вывести только строку "greeting" из объекта data используя всё те же фигурные скобки:


<div id="vue-instance">
  Введите приветствие: <input type="text" v-model="greeting">
    <p>{{ greeting }}</p>
</div>

See the Pen Vuejs-basics#2 by kamil Ocean (@kamil-ocean) on CodePen.

Как вы видите Vue делает привязку данных реально легкой. Вам не нужно писать какой-либо обработчик события ввода в поле <input> на чистом JS или JQuery, всё что вам нужно, это добавить v-model директиву чтобы связать элемент ввода с данными Vue. Если мы взглянем на весь код, то мы реально можем заметить и выразить благодарность Vue за то, насколько он абстрагировался и упростил логику обработки событий:


<body>

<div id="vue-instance">
    Enter a greeting: <input type="text" v-model="greeting">
    <p>{{ greeting }}</p>
</div>

<script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>

<script>

    var vm = new Vue({

        el: '#vue-instance',
        data: {

            greeting: 'Hello VueJs!'

        }

    });

</script>

</body>>

Обработка событий с помощью v-on

Vue.js прослушивает события DOM и беззаботно назначает обработчики событий с помощью директивы v-on, вы можете прикрепить слушателя события к элементу создав метод в вашем экземпляре Vue и назначить обработчик клика.

В этом примере, мы создаем метод, который называется sayHello в объекте methods, который отображает alert всплывающее окно с именем пользователя, который зашел сюда. Метод sayHello назначен как обработчик клика click для кнопки используя для этого директиву v-on:click


<div id="vue-instance">
  Enter your name: <input type="text" v-model="name">
  <button v-on:click="sayHello">Hey there!</button>
</div>

<script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>

<script>

  var vm = new Vue({

    el: '#vue-instance',
    data: {

      name: ''

    },
    methods: {

      sayHello: function(){

        alert('Hey there, ' + this.name);

      }

    }

  });
</script>

See the Pen Vuejs-basics#2 by kamil Ocean (@kamil-ocean) on CodePen.

Конечно вы не ограничены в использовании только события click, так как директива v-on поддерживает общие JavaScript события, такие как v-on:mouseover, v-on:keydown, v-on:submit, v-on:keypress и т.д. или даже ваше собственное самоопределенное событие.

Когда-нибудь вы заметете, что используете директиву v-on слишком часто в процессе разработки. Vue предоставляет нам короткое обозначение этой директивы с помощью символа @. Теперь вы можете заменить эту директиву в нашем предыдущем примере на версию с @


<button v-on:click="sayHello">Hey there!</button>

<button @click="sayHello">Hey there!</button>

Рендеринг с условиями v-if и v-show

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

Используя то, чему мы научились в предыдущем примере о навешивании обработчиков событий с помощью v-on, мы можем сделать простой метод login, который переключает значение isLoggedIn в true или false, когда пользователь кликнул кнопку login или logout.

Когда значение isLoggedIn изменяется, Vue будет автоматически пересматривать условие в v-if директиве и выводить правильную часть контента в зависимости от выполнения условия.


<div id="vue-instance">
  <div v-if="isLoggedIn">
    Welcome to coligo!
    <button @click="login" type="submit">Logout</button>
  </div>
  <div v-else>
    <input type="text" placeholder="username">
    <input type="password" placeholder="password">
    <button @click="login" type="submit">Login</button>
  </div>
</div>

<script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>

<script>

  var vm = new Vue({

    el: '#vue-instance',
    data: {

      isLoggedIn: false

    },
    methods:{

      login: function(){

        // 'this' refers to the vm instance
        this.isLoggedIn = !this.isLoggedIn;

      }

    }

  });
</script>

</body>

See the Pen Vuejs-basics#4 by kamil Ocean (@kamil-ocean) on CodePen.

Так же вы можете использовать v-show, вместо v-if. Заменив v-if в нашем предыдущем примере, на v-show:


<div id="vue-instance">
  <div v-show="isLoggedIn">
    Welcome to coligo!
    <button @click="login" type="submit">Logout</button>
  </div>
  <div v-else>
    <input type="text" placeholder="username">
    <input type="password" placeholder="password">
    <button @click="login" type="submit">Login</button>
  </div>
</div>

Однако, есть разница в том как они показывают и скрывают контент.

v-show всегда будет рендерить контент независимо от истинности выражения, тогда как v-if рендерит контент только если выражение истино.

Также, всякий раз, когда значение выражения переключается между true и false, v-if будет полностью разрушать и реконструировать элемент, в то время, как v-show просто будет переключать CSS свойство display элемента, чтобы показать или скрыть элемент.

Хотя эти различия кажутся не такими значимыми для вас в данный момент, они очень пригодятся когда речь зайдет о производительности ваших больших проектов. VueJS guide описывает это так:

В большинстве случаев, v-if обходится дороже в производительности, в отличии как v-show. Отдавайте предпочтение v-show если вам нужно переключать что-то очень часто и используйте v-if если это с малой вероятностью будет производится в "runtime" на лету.

Рендерим Список (List) с помощью v-for

Предположим, у нас есть online магазин и нам нужно отобразить все товары, которые у нас есть. v-for директива позволяет рендерить нам основанные на содержании значения массива используя специальный синтаксис: товар in склад. Это может быть прочитано как "для каждого товара в складе".

Мы создадим этот гипотетический склад (массив) и выведем его на страницу используя директиву v-for, которая в результате будет также выводить несколько li элементов содержащие название и цену каждого товара в нашем магазине:


<body>

  <div id="vue-instance">
    <ul>
      <li v-for="item in inventory">
        {{ item.name }} - {{ item.price }}
      </li>
    </ul>
  </div>

  <script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>

  <script>
  var vm = new Vue({
    el: '#vue-instance',
    data: {
      {name: 'Венера', price: 100},
      {name: 'Анжелика', price: 180},
      {name: 'Милена', price: 140},
      {name: 'Каролина', price: 200}
    }
  });
  </script>

</body>

See the Pen Vuejs-basics#5 by kamil Ocean (@kamil-ocean) on CodePen.

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

Иногда вам возможно потребуется доступ к Index (порядковому номеру) вашего цикла, для этого Vue предоставляет 2 решения:

Использвать специальную переменную $index


<div id="vue-instance">
  <ul>
    <li v-for="item in inventory">
      {{ $index }} - {{ item.name }} - {{ item.price }}
    </li>
  </ul>
</div>

Или использовать alias

Примичания переводчика: Если вы загляните в оригинал статьи, то поймёте, что у этого чувака ни чего не работает, он не правильно поставил (index, item) надо наоборот. Также я добавил в пример увеличение index на 1, так как нумерация массива понятное дело начинается с 0, не по человечески выглядело.


<div id="vue-instance">
  <ul>
    <li v-for="(item, index) in inventory">
      {{ index + 1 }} - {{ item.name }} - {{ item.price }}
    </li>
  </ul>
</div>

See the Pen Vuejs-basics#6 by kamil Ocean (@kamil-ocean) on CodePen.

Вычисляемые свойства

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

Вы предоставляете пользователю поле для ввода числа и после его ввода, автоматически возвращаете удвоенное число (то есть помноженое на 2). Обычно вы бы вешали event listener (обработчик события), который бы ожидал события на input и не зависимо от того, когда произошло событие, вы умножаете результат на 2. VueJS делает такие вещи гораздо более прямолинейно используя вычисляемые свойства (Computed properties):


<body>

  <div id="vue-instance">
      <input type="number" v-model="x">
      result: {{ doubleX }}
  </div>

  <script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>

  <script>
  var vm = new Vue({
    el: '#vue-instance',
    data: {
      x: 1
    },
      computed: {
          doubleX: function(){
              return this.x*2;
          }
      }
  });
  </script>

</body>

See the Pen Vuejs-basics#7 by kamil Ocean (@kamil-ocean) on CodePen.

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

Давайте сделаем простую маленькую игру, чтобы показать другой пример вычисляемых свойств: спрашиваем у пользователя число от 1 до 10 и если он угадывает, то выводим сообщение: "ты угадал", иначе сообщение: "попробуй снова".

Мы установим случайное число как 5 чтобы начать, и при каждой догадке пользователя, мы будем генерировать это число случайным образом. Используя то, что мы изучали в прошлой секции и объединяя это с вычисляемыми свойствами, мы можем легко написать эту игру.


<body>

  <div id="vue-instance">
      Guess a number between 1 and 10: <input type="number" v-model="userInput">
      <b>{{ message }}</b>
  </div>

  <script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>

  <script>
      var vm = new Vue({
          el: '#vue-instance',
          data: {
              userInput: 0,
              randomNumber: 5
          },
          methods: {
              getRandomNumber: function(min, max){
                  return Math.floor(Math.random() * (max - min + 1)) + min;
              }
          },
          computed: {
              message: function(){
                  if (this.userInput == this.randomNumber) {
            this.randomNumber = this.getRandomNumber(1, 10);
                      return 'You got it right!';
                  } else {
            this.randomNumber = this.getRandomNumber(1, 10);
                      return 'Try again!';
                  }

              }
          }
      });
  </script>

</body>

See the Pen Vuejs-basics#8 by kamil Ocean (@kamil-ocean) on CodePen.

Подведём итоги

Ну чтож, мы сделали это! VueJs это, как я думаю, один из самых легких и элегантных библиотек для изучения. Он построен на твёрдых основах философии проектирования и очень быстро набирает популярность. Библиотека мало весит и имеет низкий входной порог и быстро повышает вашу продуктивность. Мы описали основы VueJS в этом туториале с некоторыми примерами, которые иллюстрируют ключевые подходы, в частности: