Основы Vue.js 1.0 (базовые концепции) > stdout.in Ievgen Kuzminov IT blog

Основы Vue.js 1.0 (базовые концепции)

03 нояб. 2015 г., 8:16:28

vue

Перевод статьи из блога Evan You "VUE.JS: A (RE)INTRODUCTION". Переведён прямой речью от лица автора.

Не забывайте, что мы переводим документацию Vue.js на русский язык. Присоединяйтесь! Детали тут.

Vue.js это библиотека для построения веб интерфейсов. В связке с некоторыми инструментами её даже можно назвать “фрэймворк”, однако это скорее набор необязательных инструментов, которые работают вместе действительно хорошо. Сейчас, если вы не слышали о Vue.js и не пользовались им раньше, вы думаете: "Какое счастье, ещё один скучный JavaScript фрэймворк!" Я понимаю это. Действительно, Vue не такая уж и новинка — впервые я начал работу над его прототипом почти два года назад, а первый публичный релиз произошёл в феврале 2014. С течением времени он эволюционировал и сейчас многие пользуются Vue.js в production.

Так что же предлагает Vue? Чем отличается от конкурентов? Что должно заставить вас изучать эту библиотеку, в то время как уже существуют Angular, Ember и React? Эта статья прольёт свет на эти вопросы, проведя вам короткий экскурс в мир концепций Vue.js. Надеюсь, по прочтению, вы получите ответы на ваши вопросы.

РЕАКТИВНОСТЬ. REACTIVITY.

Поддерживать синхронизацию состояния данных и отображения тяжело. Или нет?

Начнём с наиболее простой задачи: отображение данных. Предположим у нас есть простой объект:

var object = {
  message: 'Hello world!'
}

И шаблон:

<div id="example">
  {{ message }}
</div>

И вот как мы соединяем данным и шаблон при помощи Vue:

new Vue({
  el: '#example',
  data: object
})

Похоже мы только что отрендерили шаблон. Что нужно сделать, чтобы отображение поменялось после изменения данных в объекте? Ничего! Vue сконвертировала объект и сделала его "реактивным". Установив object.message другое значение, HTML будет обновлён автоматически. Что более важно, ет необходимости $apply в таймаутах, или вызывать setState(), или "слушать" события хранилища, или делать свойства отслеживаемыми, как ko.observable() или Ember.Object.create()… в нашем случае оно "просто работает".

Vue также предоставляет вычисляемые свойства:

var example = new Vue({
  data: {
    a: 1
  },
  computed: {
    b: function () {
      return this.a + 1
    }
  }
})
// оба a & b обрабатываются при вызове на объекте.
example.a // -> 1
example.b // -> 2
example.a++
example.b // -> 3

Вычисляемое свойство b отслеживает a как зависимость и автоматически синхронизируется. Нет необходимости указывать зависимости явно.

КОМПОНЕНТЫ. COMPONENTS.

Привязка данных хороша для небольших демо. Но что по поводу больших приложений?

Когда речь заходит за структурирование сложных интерфейсов, Vue следует подходу близкому с React: её компоненты везде и всюду. Давайте сделаем из нашего примера компонент, который можно повторно использовать:

var Example = Vue.extend({
  template: '<div>{{ message }}</div>',
  data: function () {
    return {
      message: 'Hello Vue.js!'
    }
  }
})

// зарегистриуем тег <example>
Vue.component('example', Example)

Теперь можно использовать компонент в других шаблонах просто как кастомный элемент:

<example></example>

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

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

МОДУЛЬНОСТЬ. MODULARITY.

На дворе 2015 год и мы не должны помещать всё в глобальную область видимости!

Давайте пользоваться сборщиками модулей (Webpack или Browserify) и плюшками ES2015. Каждый компонент может просто быть отдельным модулем. А т.к. Vue автоматически сконвертирует объект с опциями в конструктор компонента, можно просто экспортировать объект:

// ComponentA.js
export default {
  template: '<div>{{ message }}</div>',
  data () {
    return {
      message: 'Hello Vue.js!'
    }
  }
}
// App.js
import ComponentA from './ComponentA'

export default {
  // объявляем компонент только это этой области видимости 
  // ComponentA связан с тегом <component-a>
  components: { ComponentA },
  template: `
    <div>
      <p>Now I'm using another component.</p>
      <component-a></component-a>
    </div>
  `
}

Неплохо, да? А может будет ещё лучше, если мы вложим шаблон компонента, стили и JavaScript логику в один файл? С инструментами Webpack + vue-loader или Browserify + vueify можно сделать так:

<!-- MyComponent.vue -->

<!-- css -->
<style>
.message {
  color: red;
}
</style>

<!-- template -->
<template>
  <div class="message">{{ message }}</div>
</template>

<!-- js -->
<script>
export default {
  props: ['message'],
  created() {
    console.log('MyComponent created!')
  }
}
</script>

Подождите, мы только что снова изобрели Web Components? Но здесь же глобальный CSS!

Да, почти, с некоторыми особенностями:

  • Стили можно инкапсулировать. Просто добавьте аттрибут области видимости в тег <style>. И область видимости стилей не "утекает" во вложенные компоненты.
  • Все компоненты Vue компилируются в модуль JavaScript и не требуют полифилов для работы вплоть до IE9. Также можете обернуть их настоящим Custom Element-ом если хотите.
  • ES2015 поддерживается по-умолчанию в тегах <script>.
  • Можно использовать любые пре-процессоры в любом блоке компонента.
  • Используя Webpack + vue-loader, можно применить всю мощь Webpack-а для обработки статических файлов. Т.к. шаблоны и стили проходят черех html-loader и css-loader, которые могут обрабатывать URL к фалам как зависимость.

Так что, да. Можно получить компонент, который выглядит вот так:

vue

О, а я упоминал, что компоненты Vue поддерживают "горячую" перезагрузку?

hot reload

АНИМАЦИИ. ANIMATIONS.

Могул ли я делать разные красивые штуки с Vue?

Vue имеет встроенную систему анимаций переходов. Очень простую в использовании. Множество признанных интерактивных сайтов использую её.

Реактивная систем Vue также делает задачу анимации переходов состояний тривиально простой. Что в свою очередь совсем не так просто для фрэймворков с "dirty-checking" или сравнением Virtual DOM. При анимации перехода состояний с частотой 60 кадров в секунду, Vue достоверно знает какие связанные данные изменены и эффективно обновляет связанное представление этих данных. В то время как остальное приложение не затрагивается вовсе. В случае других подходов, dirty checking и сравнения Virtual DOM, изменение любой части состояния данных означает, что все под-дерево (области видимости или компонент) требует обновление / перерисовки. Если это работает достаточно быстро в небольших демо, то скорее триггерить изменения 60 раз в секунду станут проблемой для большого приложения. Даже если удастся ускорить это, то разряженная батарея устройств не скажет вам спасибо за все "холостые" циклы. Посмотрите эту лекцию, чтобы понять каких усилий стоит сделать эффективные анимации в React. Приложения на Vue оказываются просто по-умолчанию оптимизированными для таких сценариев использования.

Пример анимации переходов, управляемых состоянием, в Vue:

See the Pen Vue.js elastic header component by Evan You (@yyx990803) on CodePen.

МАРШРУТИЗАЦИЯ. ROUTING.

Итак, я хочу сделать приложение, но где роутер ?

Как и React, Vue сам по себе не идёт в поставке с маршрутизацией. Но есть пакет vue-router, который поможем в этом. Он поддерживает маршрутизацию вложенных маршрутов к вложенным компонентам и предлагает продвинутый контроль переходов. Вот простой пример:

import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './app.vue'
import ViewA from './view-a.vue'
import ViewB from './view-b.vue'

Vue.use(VueRouter)

const router = new VueRouter()

router.map({
  '/a': { component: ViewA },
  '/b': { component: ViewB }
})

router.start(App, '#app')

The template for app.vue:

<div>
  <h1>This is the layout that won't change</h1>
  <router-view><!-- matched component renders here --></router-view>
</div>

Настоящий полномасштабный пример вы можете найти в примере клона HackerNews, который сделан при помощи Vue.js, vue-router, Webpack и vue-loader.

СТАБИЛЬНОСТЬ. STABILITY.

Доморощенный проект? Ты это серьёзно?

Да, это личный проект. Так что, если вы ищете проект за плечами которого стоят монстры индустрии, Vue не из таких. Но давайте взглянем на цифры. У Vue 100% тестовое покрытие на каждом коммите начиная с большого переписывания версии 0.11. Так будет и в будущем. Багрепорты на GitHub закрываются в среднем за 13 часов, и закрыто уже более 1400+ штук. На момент написания этого поста не существует открытых и воспроизводимых ошибок.

Vue совсем недавно достиг версии 1.0, что означает готовность к продакшн использованию. API будет оставаться стабильным. Для перехода 0.12 -> 1.0 существует миграционный билд, со всеми новыми возможностями и полной обратной совместимостью. Сообщения об использовании устаревшего функционала облегчат процесс обновления. Так же планируется поступать во всех будущих апдейтах без полной обратной совместимости.

Итак, надеюсь мне удалось убедить хотя бы кого-то взглянуть на Vue детальнее. Я верю, что Vue является достойной альтернативой существующим фрэймворкам и буду рад видеть, как вы делает чудесные вещи с его помощью. Ознакомьтесь детальнее с документацией или почитайте форум и gitter канал (прим.перев. канал русскоязычного сообщества Vue.js). И... даже если вы не хотите использовать Vue подписывайтесь на мой Twitter (прим.перев. "Да, Эван пишет толковые вещи про JS").

comments powered by Disqus
Евгений
Кузьминов "iJackUA"
Web Team Lead
в MobiDev (Харьков, Украина)
Code in Ruby and Elixir, but still love PHP. Explore ES6 and Vue.js. Explore databases, use Ubuntu and MacOS, think about IT people and management

Заметки


Ansistrano- ansistrano.deploy and ansistrano.rollback are Ansible Galaxy roles to easily manage the deployment process for scripting applications such as PHP, Python and Ruby. It's an Ansible port for Capistrano.