В данной статье речь пойдет о замечательном фронтенд фреймворке Vue.js. Как вы видите, статья называется «Vue.js для сомневающихся», и, если вы до сих пор не могли решиться попробовать Vue.js на практике, то надеюсь, что после прочтения вы все-таки на это решитесь.
Фреймворки разрабатываются для того, чтобы упростить нам жизнь и освободить от написания однотипного кода. Но, по мере того как кодовая база некоторых фреймворков сильно разрастается, они начинают привносить свою долю сложности в проект. Из-за этого при планировании разработки мы должны учитывать два фактора:
- сложность нашего приложения
- сложность фреймворка, который мы используем
Немного абстрагируемся и назовём это внутренней сложностью (то есть сложностью, от которой мы не можем избавиться при разработке) и сложностью инструмента, с помощью которого мы достигаем той или иной цели. Естественно манипулировать мы можем только сложностью инструмента.
Из вышесказанного, у нас получается два варианта выбора инструмента:
- Вариант недостаточности. Когда инструмента недостаточно, чтобы перекрыть внутреннюю сложность. Функции, необходимые для реализации приложения, отсутствуют в фреймворке, и нам приходится вручную дорабатывать и добавлять необходимый инструментарий.
- Вариант избыточности. Когда необходимый для приложения функционал перекрывается только небольшой частью инструмента. Остальная же часть инструментария висит мертвым грузом и только создает нам проблемы: ограничения при разработке, замедление загрузки приложения и т.п.
Так что же делать? Возможно, буду немного Капитаном Очевидностью, но надо действовать по принципу: “Для каждой цели — свой инструмент”. При планировании нам необходимо искать золотую середину так, чтобы сложность (и, следовательно, функциональность) приложения были на одном уровне.
О Vue.js и авторе
Итак, разберемся с Vue и каким образом он может облегчить нам разработку приложения.
Создателем Vue.js является Evan You, бывший сотрудник Google и Meteor Dev Group. Начал он разрабатывать фреймворк в 2013-м, а в феврале 2014-го состоялся первый публичный релиз. Vue широко используется среди китайских компаний, например: Alibaba, Baidu, Xiaomi, Sina Weibo и др. Он входит в ядро Laravel и PageKit. Недавно свободная система управления репозиториями GitLab тоже перешла на Vue.js.
В конце сентября 2016-го вышел в релиз Vue.js 2.0, еще круче и с упором на производительность — теперь используется виртуальный DOM, поддерживается серверный рендеринг, возможность использовать JSX и т.д. Хотя сейчас он поддерживается только сообществом, он держится достойно даже на уровне продуктов таких гигантов, как Google и Facebook (Angular2 и React 15), и постепенно догоняет их по популярности.
Рассмотрим самый простой пример:
app.js
var demo = new Vue({
el: '#demo',
data: {
message: 'Hello, Singree!'
}
})
- создается новый инстанс вью через new Vue
- в el мы определяем, за каким элементом следит вью
- в data у нас объект состояния
app.html
<div id="demo">
<p>{{message ? message : "no content"}}</p>
<input v-model="message">
</div>
- в html, естественно, у нас должен быть элемент с нужным нам селектором
- данные из состояния выводим в усатом (mustache ведь) синтаксисе. Тут у нас обычное тернарное выражение
- инпут связываем со значением message объекта состояния с помощью директивы v-model
//codepen.io/Demetrius/embed/KNaJLW/?height=468&theme-id=16150&default-tab=result
Концепции Vue.js
Основными концепциями Vue являются:
- конструктор
- компоненты
- директивы
- переходы
В первой версии еще были фильтры, но, насколько я знаю, в текущей версии они считаются deprecated.
Конструктор
app.js
new Vue({
el: '<jQueryStyleSelector>',
template: '<id || inline template>',
data: {
props: 'Это видно в шаблонах',
first_name: "Вася",
last_name: "Пупкин"
},
computed: {
full_name: function(){
return this.first_name + this.last_name; //Вася Пупкин
}
},
methods: {
// методы жизненного цикла
beforeCreate: function(){},
created: function(){},
beforeMount: function(){},
mounted: function(){},
beforeUpdate: function(){},
updated: function(){},
beforeDestroy: function(){},
destroyed: function(){},
customMethodsAlso: function(){
//здесь у нас тоже есть доступ к data
}
}
})
Работа с Vue.js начинается с создания нового инстанса new Vue. В el у нас элемент, за которым следит Vue. В template выбран (либо прописан инлайново) элемент, куда Vue будет рендерить. В data хранится текущее состояние инстанса, а метод computed предоставляет нам вычисляемые свойства.
В примере вычисляемое свойство full_name отслеживает first_name и last_name как зависимости и автоматически синхронизируется.
В methods можно выделить следующие кастомные методы и методы жизненного цикла Vue:
- beforeCreate — смотрит данные и инициализирует события
- created — смотрит, есть ли el или template. Если есть, то рендерит в них; если нет, то ищет метод render
- beforeMount — создает vm.$el и заменяет им el
- mounted — элемент отрендерен
При изменении состояния:
- beforeUpdate — снова рендерит VDOM и сравнивает с реальным DOM-ом, применяет изменения
- updated — изменения отрендерены
- beforeDestroy — полный демонтаж вотчеров, внутренних компонентов и слушателей событий
- destroyed — вызывается, когда выполнение операции останавливается
Директивы
Директивы — специальные атрибуты для добавления элементам html дополнительной функциональности.
Рассмотрим некоторые встроенные директивы (кто работал с Angular, тому они покажутся очень знакомыми):
- V-bind — динамически связывается с одним или несколькими атрибутами.
- V-cloak — прячет “усатые” выражения, пока не подтянулись данные
- v-if — условие для рендера элемента
- V-else — обозначает “else блок” для v-if
- V-for — циклично проходит массив объектов
- V-model — связывает состояние с input элементом
- V-on — связывает слушателя события с элементом
- V-once — рендерит элемент только вначале и больше не следит за ним
- V-pre — не компилирует элемент и его дочерние элементы
- V-show — переключает видимость элемента, изменяя свойство CSS display
- V-text — обновляет textContent элемента
Все Vue-директивы имеют префикс “v-”. В директиву передается какое-то значение состояния, а в качестве аргументов могут быть атрибуты html или события.
html
<div v-my-directive="someValue"></div>
js
Vue.directive('my-directive', {
bind: function () {
// подготовительные работы
// добавление слушателей событий и других ресурсоемких функций,
// которые должны быть запущены только один раз
},
update: function (newValue, oldValue) {
// делаем что-то с обновленным значением
},
unbind: function () {
// производим очистку
// удаляем слушателей событий, добавленных в bind()
}
})
Компоненты
Компоненты помогают расширить основные html элементы и внедрить переиспользуемый код. По сути, компоненты — повторно используемые части UI. На этапе проектирования мы разбиваем наше приложение на независимые части и получаем древовидную структуру компонентов.
В Vue.js нет особых требований к именам компонентов, но хорошая практика — придерживаться правил W3C насчет кастомных компонентов, то есть буквы нижнего регистра и разделения через дефис.
app.js
Vue.component('simple-counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
}
})
new Vue({
el: '#demo'
})
Новый компонент объявляется с помощью Vue.component, и в первый аргумент мы передаем имя нового тега (в нашем случае simple-counter)
//codepen.io/Demetrius/embed/ObgyQP/?height=468&theme-id=16150&default-tab=result
Коммуникация между vue-компонентами осуществляется по принципу “Props in, Events out”. То есть от родительского элемента к дочернему информация передается через пропсы, а обратно — вызываются события.
Также во Vue.js есть так называемые однофайловые компоненты. Мы создаем файл с расширением .vue и пишем туда стили, шаблон и логику. Причем писать можно на любом удобном вам препроцессоре (SASS, Stylus, PostCSS, Jade, ...) и языке, компилирующимся в JS (CoffeeScript, TypeScript).
app.js
// comment.vue
<style lang="sass">
button {
border: 1px solid gray;
&.blue { border-color: blue; }
}
</style>
<template lang="jade">
avatar(:user='user')
input(type='text', v-model='content')
button.blue(@click='submitComment')
</template>
<script>
import Comment from '../models'
import avatar from './components/avatar.vue'
export default {
props: ['user'],
components: {
avatar
},
data () {
return {
content: ''
}
},
methods: {
submitComment (e) {
e.preventDefault();
var comment = new Comment(this.content)
comment.save().then(() => {
alert('o_O')
this.content = ''
})
}
}
}
</script>
Переходы
Vue предоставляет различные способы применения анимационных эффектов, когда элементы отрисованы, обновлены или удалены из DOM. Они включают в себя инструменты для:
- автоматического применения классов для CSS-переходов и анимаций
- интеграции сторонних библиотек для CSS-анимаций, таких как Animate.css
- использования JavaScript для манипуляции DOM-ом
- интеграции сторонних JavaScript библиотек для анимаций, таких как Velocity.js
Рассмотрим простой пример:
html
<div id="demo">
<button @click="show = !show">Toggle show</button>
<transition name="bounce">
<p v-if="show">Look at me!</p>
</transition>
</div>
js
new Vue({
el: '#demo',
data: {
show: true
}
})
//codepen.io/Demetrius/embed/ZByQzx/?height=490&theme-id=16150&default-tab=result
Экосистема фреймворка
Роутинг
Во Vue.js за маршрутизацию отвечает отдельный пакет vue-router. Он поддерживает вложенные маршруты к вложенным компонентам, предлагает упрощенное API для навигационных хуков, управляемое поведение скрола и продвинутый контроль переходов.
Вот небольшой пример:
app.js
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')
app.vue
<div>
<h1>Это шаблон, который не будет меняться</h1>
<router-view><!-- выбранные компоненты рендерятся здесь --></router-view>
</div>
Ajax-запросы
Для работы с Ajax-запросами существует плагин vue-resource. Он предоставляет возможности для создания веб-запросов и обработки ответов с помощью XMLHttpRequest или JSONP. Также особенностью плагина является поддержка Promise API и URI шаблонов.
Пример:
js
{
// GET /someUrl
this.$http.get('/someUrl').then((response) => {
// успех
}, (response) => {
// или ошибка
});
}
Управление состоянием
Vuex — паттерн и библиотека управления состоянием для приложений на Vue.js. Он предоставляет централизованное общее состояние для всех компонентов в приложении и правила, обеспечивающие предсказуемое изменение состояния.
На изображении ниже представлено приложение на Vue+Vuex со следующими частями:
- Состояние (State), которое является единственным источником данных для компонентов.
- Vue-компоненты(Vue-components), которые по сути являются лишь декларативным отображением состояния.
- Действия (Actions), которые отлавливают событие, которое произошло, собирают данные с внешних API и запускают нужные мутации.
- Мутации (Mutations) — единственная часть, которая может изменять состояние и, получив данные от Actions, применяет их на состоянии.
Система сборки и инструменты разработчика
Для отладки в браузере существует Vue-devtools (к сожалению, пока только для Chrome), который позволяет видеть, какие компоненты есть в нашем приложении и их текущее состояние.
Также он прекрасно работает с Vuex и позволяет выполнять так называемый time-travel debugging: в браузере мы можем увидеть историю состояний и переключаться между ними.
Почему я должен его использовать
Vue удивителен! Я считаю, это здорово, что я могу просто подключить его на странице и начать работать без необходимости шаманить с системой сборки или CLI. С ним очень просто начать работать, даже если вы никогда не работали с JavaScript фреймворками. Это идеальное сочетание удобства и мощности. Рассмотрим еще несколько аргументов в его пользу:
- Теперь он еще меньше. Runtime сборка Vue.js 2.0 весит всего лишь 16kb, а вместе с vue-router и vuex — 26kb (примерно как и ядро первой версии).
- Он еще быстрее. Во Vue.js всегда уделялось большое внимание быстродействию. Прослойка, отвечающая за рендеринг, переписана на облегченную реализацию виртуального DOM-а — форка Snabbdom.
- Vue 2.0 поддерживает серверный рендеринг. Для этого есть модуль Vue-server-renderer, поддерживающий другие инструменты из экосистемы Vue (vue-router и vuex). Теперь гораздо проще создавать изоморфные приложения.
- Ребята из Alibaba работают над Weex, кроссплатформенным нативным мобильным UI (как ReactNative и NativeScript). Отныне Vue-компоненты можно будет использовать для веб, Android и iOS.
Vue прошёл путь от небольшого аматорского проекта до широко используемого проекта с большим сообществом, а я надеюсь, что сумел развеять ваши сомнения по поводу того, стоит использовать этот фреймворк или нет.
Спасибо за внимание!
Статью подготовили: greebn9k (Сергей Грибняк), Dmitry-Ivanov (Дмитрий Иванов), silmarilion (Андрей Хахарев)