Одна из моих любимых вещей в ((http://vuejs.org/ Vue.js)) - он работает на простейших страницах с простейшими компонентами. Вам не нужны никакие сложные инструменты сборки или деревья зависимостей.
Но Vue не ограничивается только простыми компонентами. ((https://github.com/vuejs/vue-resource Vue-resource)) делает AJAX простым, с ((http://vuejs.github.io/vue-router/en/ vue-router)) можно настроить маршрутизацию одностраничного приложения почти без усилий. И я обещаю, когда-нибудь я выучу и ((https://github.com/vuejs/vuex Vuex)).
Я хочу показать вам, насколько просто использовать vue-router для создания одностраничного приложения с помощью Vue. И уж поверьте мне - это просто. Если вы уже создавали свой компонент с помощью Vue, то 90% работы позади.
== Настройка ==
Как это часто бывает, в качестве инструмента для сборки я выбрал ((https://laravel.com/docs/elixir Laravel Elixir)).
Вы можете использовать любую систему сборки, которая предоставляет вам доступ к вашим NPM-пакетам. Или вы можете включить пакет в сборку вручную (с помощью ((https://cdnjs.cloudflare.com/ajax/libs/vue-router/0.7.10/vue-router.min.js CDN)) ) или с помощью Bower. В итоге вам нужен %%(t)vue-router%%, установленный любым способом. Если вы не собираетесь использовать Elixir, то просто пропустите следующий раздел.
=== Установка Vue и vue-router с помощью Laravel Elixir (не обязательно) ===
Если вы собираетесь начать новый проект используя Laravel Elixir, прочтите документацию с инструкциями по базовой установке. Затем добавьте %%(t)vue%% и %%(t)vue-router%%:
%%(sh)
npm install vue vue-router --save
%%
Далее вам надо добавить задачу Browserify для вашего JavaScript файла:
%%(js)
// gulpfile.js
elixir(function (mix) {
mix.browserify('app.js');
});
%%
Теперь ожидается, что у вас есть файл %%(t)resources/assets/js/app.js%%, который будет передаваться через Browserify и Babel и выводиться в %%(t)public/js/app.js%%. Создайте "ресурсную" версию этого файла и выполните %%(sh)gulp watch%%, чтобы запустить его.
=== Включение зависимостей ===
Вам надо включить Vue и vue-router в свой основной JavaScript файл с помощью любой доступной вам системы импорта:
%%(js)
var Vue = require('vue');
var VueRouter = require('vue-router');
Vue.use(VueRouter);
%%
Мы включили Vue и vue-router, и затем связывали их друг с другом. Теперь давайте напишем наше приложение.
== Создание своего приложения ==
Как в любом Vue-приложении, нам надо создать базовое приложение. Но в отличие от других Vue-приложений, ядро шаблонной работы, которую мы будем делать, это отображение нескольких компонентов по нескольким маршрутам. Во Vue нет такого нового понятия как "страница", каждая страница - это просто компонент, который может содержать другие компоненты.
Давайте создадим наше приложение и наш маршрутизатор:
%%(js)
var App = Vue.extend({});
var router = new VueRouter();
router.start(App, '#app');
%%
Вот и всё! Оно не будет ничего делать, потому что мы не отобразили ни одного маршрута, но мы определили приложение, определили маршрутизатор, собрали их воедино, и затем инициализировали маршрутизатор.
== Отображение компонентов по маршрутам ==
У нас есть приложение и маршрутизатор, давайте определим несколько маршрутов:
%%(js)
var App = Vue.extend({});
var router = new VueRouter();
var Home = Vue.extend({
template: 'Добро пожаловать на главную страницу!'
});
var People = Vue.extend({
template: 'Посмотрите на всех, кто тут работает!'
});
router.map({
'/': {
component: Home
},
'/people': {
component: People
}
});
router.start(App, '#app');
%%
Мы определили два возможных маршрута в нашем приложении и указали компонент для каждого из них.
== Сборка HTML-страницы ==
Давайте создадим HTML-страницу для размещения нашего маршрутизатора. Этой странице не обязательно быть полностью пустой, как вы могли бы подумать. При использовании vue-router ваше приложение может содержать какой-либо код, и он не будет отключен из-за использования компонентов, например, это может быть панель навигации.
%%(html)
...
...
%%
Предположим, у этой страницы есть HTML-заголовок и блочные теги, а также она импортирует наши скрипты и зависимости где-нибудь в заголовке или подвале.
Здесь мы видим несколько важных вещей. Во-первых, когда мы запустили наш маршрутизатор в скрипте, мы связали его с '#app', поэтому нам надо создать элемент страницы с ID = "app", с которым мы свяжем наше Vue-приложение.
Во-вторых, здесь использован Vue-синтаксис для ссылок - используется свойство %%(t)v-link%% и передаётся в JSON-объект. Мы будем делать так: %%(t){ path: '/url-here' }%%.
.(alert)
Если открываемая в данный момент ссылка "активна" (открыта у пользователя), маршрутизатор применит для неё класс %%(t)v-link-active%%, и вы сможете настроить для неё уникальный стиль. Также вы можете изменить этот класс или применять его для отдельных связанных элементов, таких как родительские %%(t)div%% или %%(t)li%% - вы можете узнать больше из документации.
И наконец, у нас есть компонент %%(t)%%, сюда будет приходить вывод каждого компонента.
Если вы зайдёте на эту страницу, и всё корректно загрузится, значит вы сделали своё первое одностраничное приложение с помощью vue-router!
.(alert)
Вы могли заметить, что сейчас в нём используется шебанг-стиль навигации, то есть все ваши маршруты начинаются с %%(t)#!%%. Это можно отключить, мы поговорим об этом позже, но приготовьтесь, потребуется немного танцев с бубном.
== Более продвинутое определение маршрута ==
Выше мы определили несколько довольно простых маршрутов. Давайте копнём немного глубже в направлении типов маршрутов, которые можно определить с помощью vue-router.
=== Параметры маршрута ===
Возможно вам понадобится определить более сложные маршруты, чем просто статические URL.
Мы будем вызывать URL, которые могут соответствовать нескольким "динамическим" URL. Посмотрим, как определить такой маршрут.
%%(js)
router.map({
'/people/:personId': {
component: {
template: 'Person ID is {{$route.params.personId}}'
}
}
});
%%
Из этого примера мы можем узнать несколько вещей.
Во-первых, мы видим, что vue-router отображает динамические параметры используя такой синтаксис: %%(t):paramName%%.
Во-вторых, мы видим, что vue-router позволяет при желании определять объекты компонентов в строку.
И в-третьих, мы видим, что у нас есть доступ к объекту %%(t)$route%% со свойством %%(t)params%%, который является объектом всех подходящих параметров динамических URL.
==== Маски сегментов маршрута ====
Когда надо определить сегмент динамического маршрута, который может подходить для нескольких сегментов, используйте в начале имени сегмента **%%(t)*%%** вместо **%%(t):%%** :
%%(js)
router.map({
'/people/*greedy' => {},
'/people/*greedy/baz' => {},
});
%%
Первое определение маршрута будет подходить для %%(t)/people/a%%, %%(t)/people/a/b%%, %%(t)/people/a/b/c/d/e/f%%.
Второе определение маршрута будет подходить для %%(t)/people/a/baz%%, %%(t)/people/a/b/c/d/e/f/g/baz%% и т.д.
Оба будут возвращать сегмент %%(t)greedy%% по маршруту %%(t)$route.params.greedy%%, что эквивалентно полной строке для этого сегмента. %%(t)/people/a/b/baz%% будет возвращать %%(t){ greedy: 'a/b' }%%.
=== Именованные маршруты ===
Если вы когда-либо использовали маршруты Laravel, то вы уже знакомы с идеей - давать любому маршруту "имя", на которое можно ссылаться позже. С vue-router это тоже возможно:
%%(js)
router.map({
'/people/:personId': {
name: 'people.show',
component: People
}
});
%%
Далее вы можете ссылаться на этот маршрут с помощью %%(t)v-link%%:
%%(html)
Person 5
%%
=== Переход по маршруту в JavaScript ===
Мы рассмотрели, как %%(t)v-link%% может заменять обычные ссылки, а что если вам надо инициировать событие перехода в вашем JavaScript? Тут вам поможет %%(t)router.go()%%:
%%(js)
router.go({ name: 'people.show', params: { personId: 5 }});
%%
Также вы можете использовать %%(t)router.replace()%%, который работает так же, но при этом не создаёт новой записи в истории браузера.
== Настройки маршрутизатора ==
Когда вы создаёте экземпляр объекта маршрутизатора в начале вашего JavaScript-файла, вы можете передать в него несколько параметров для настройки.
* **hashbang** - если задать значение %%(t)false%%, система будет использовать настоящие URL (%%(t)/people%%) вместо шебанга (%%(t)/#!/people%%). Если вы сделаете так, то вам надо будет включить **history** и соответственно настроить свой сервер.
* **history** - использует момент отправки в браузере для обновления истории посещений в нём при переходах на сайте. Требует ((http://readystate4.com/2012/05/17/nginx-and-apache-rewrite-to-support-html5-pushstate/ правильной настройки)) вашего сервера.
* **root** - если ваше приложение находится не в корне на сервере, то задайте это свойство для указания правильной подпапки, в которой находится приложение. Например, если ваше приложение находится в %%(t)/app%%, то задайте значение %%(t)/app%%, тогда vue-router будет генерировать соответствующие URL - %%(t)/app/people%% вместо %%(t)/people%%.
.(alert)
Если вы используете это приложение внутри Laravel-приложения, то вместо настройки nginx или Apache для обработки без-шебангового состояния отправки вы можете настроить своё Laravel-приложение для его обработки. Просто установите маршрут для захвата всех валидных URL и передачи их в представление, выводящее ваш Vue-код:
%%(js)
Route::get('/{vue_capture?}', function () {
return view('home');
})->where('vue_capture', '[\/\w\.-]*');
%%
== Получение информации маршрута в ваших компонентах ==
У каждого компонента в вашем приложении будет доступ к %%(t)this.$route%%, который является "контекстным объектом маршрута" и предоставляет свойства, которые могут быть полезны для получения информации о вашем маршруте. У ваших шаблонов тоже будет доступ к этому объекту через %%(t)$route%%.
* %%(t)$route.path%% эквивалентен абсолютному пути, например, %%(t)/people%%
* %%(t)$route.params%% содержит пары ключ/значение ваших динамических разделов, например, %%(t){ personId: 5 }%%
* %%(t)$route.query%% содержит пары ключ/значение вашей строки запроса, например, %%(t)/people?sortBy=names%% будет возвращать %%(t){ sortBy : lastName }%%
* %%(t)$route.router%% возвращает экземпляр vue-router
* %%(t)$route.matched%% возвращает объекты конфигурации маршрута для каждого подходящего сегмента в текущем маршруте
* %%(t)$route.name%% возвращает имя текущего маршрута, если таковое имеется
Вы также можете передать в свои компоненты произвольные данные, передав их в определение маршрута. Например, я хочу, чтобы некоторые секции моего приложения были доступны только администратору, тогда я передаю это в виде флага в определение маршрута, а внутри компонента проверю его наличие как %%(t)$route.adminOnly%%.
%%(js)
router.map({
'/secret-admin-panels': {
component: SecretDashboard,
adminOnly: true
}
});
%%
== Настройка хуков ==
Я мог бы проверять свойство %%(t)$route.adminOnly%% в своих компонентах, но ещё лучше, если это будет обработано до того, как пользователь получит доступ к компоненту, при помощи посредника. При использовании vue-router это будут хуки маршрута, такие как %%(t)beforeEach%%:
%%(js)
// Пример проверки доступа пользователя
var MyUser = { admin: false };
router.beforeEach(function (transition) {
if (transition.to.adminOnly && ! MyUser.admin) {
transition.redirect('/login');
} else {
transition.next();
}
});
%%
Как видите, мы перехватываем запрос //перед// отрисовкой компонента. Мы можем разрешить дальнейший переход с помощью %%(t)transition.next()%%, а также мы можем перехватить пользователя и перенаправить или отменить переход - %%(t)transition.abort()%%.
Существует также хук %%(t)afterEach()%%.
== Разное ==
Ещё несколько последних замечаний.
Первое, %%(t)%% может быть передан точно так же, как и любой другой страничный компонент.
Второе, для Vue есть полное ((http://vuejs.github.io/vue-router/en/pipeline/index.html описание переходов)), которое можно использовать для определения визуального и функционального поведения при переходах между страницами.
Третье, эта статья охватывает далеко не всё, загляните в ((http://vuejs.github.io/vue-router/en/ документацию)).
== Заключение ==
Вот теперь всё. Вы увидели насколько просто настроить своё первое одностраничное приложение при помощи Vue и vue-router, и насколько плавный переход от единственного компонента к одностраничному приложению.
Если хотите посмотреть на (какой-нибудь) работающий пример использования vue-router, то можете взглянуть на обучающее приложение ((http://github.com/mattstauffer/suggestive Suggestive)), над которым я сейчас работаю.