Создаем SPA с помощью Vue и Laravel Часть 2

В этой части мы продолжим создавать Single Page Application (SPA) с помощью Vue и Laravel. В этой части мы научимся:

  • Асинхронно загружать данные из Vue компонентов
  • Обрабатывать ошибки которые возвращает наш API
  • Показывать загруженные данные нашему пользователю
  • ... и многое другое

Если вы еще не читали первую часть, то советую вам начать с нее. В ней мы настроили наше приложение, создали несколько компонентов и научились собирать собирать Javascript с помощью yarn.

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

API маршруты

SPA приложение не имеют состояния (stateless), что означает, что каждый API запрос считается новым, и не хранит состояние в сессии, как это бывает с обычными (не SPA) приложениями.

Давайте для примера зададим users маршрут, который будет возвращать список пользователей. Откройте файл routes/api.php и добавьте в него код:

Route::get('/users', function () {
  return factory('App\User', 10)->make();
});

Наш временный маршрут использует фабрику моделей для создания Eloquent Collection с моделями (без того чтобы создавать их в базе данных).

Вы должны помнить, что ко всем маршрутам заданным в файле routes/api.php автоматически добавляется префикс api. Изменить это вы можете в файле RouterServiceProvider в методе mapApiRoutes():

protected function mapApiRoutes()
{
  Route::prefix('api')
     ->middleware('api')
     ->namespace($this->namespace)
     ->group(base_path('routes/api.php'));
}

Пример ответа для маршрута users выглядит так:

[
  {
    "name":"Roel Rosenbaum I",
    "email":"[email protected]"
  },
  {
    "name":"Prof. Clarissa Osinski",
    "email":"[email protected]"
  },
  {
    "name":"Myrtle Wyman",
    "email":"[email protected]"
  },
  ...
]

Клиентские маршруты

В первой части мы добавили несколько клиентских маршрутов в файле resouces/assets/js/app.js. Напомним, чтобы добавить новый маршрут в VueRouter, необходимо создать новый объект в котором указать: имя, путь и компонент. Добавим новый маршрут users:

import UsersIndex from './views/UsersIndex';

const router = new VueRouter({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/hello',
      name: 'hello',
      component: Hello,
    },
    {
      path: '/users',
      name: 'users.index',
      component: UsersIndex,
    },
  ],
});

Компонент UsersIndex

Выше, в качестве компонента мы указали UsersIndex. Теперь нам необходимо его создать. Создайте файл resources/assets/js/views/UsersIndex.vue и добавьте в него следующий код:

<template>
  <div class="users">
    <div class="loading" v-if="loading">
      Loading...
    </div>

    <div v-if="error" class="error">
      {{ error }}
    </div>

    <ul v-if="users">
      <li v-for="{ name, email } in users">
        <strong>Name:</strong> {{ name }},
        <strong>Email:</strong> {{ email }}
      </li>
    </ul>
  </div>
</template>
<script>
import axios from 'axios';
export default {
  data() {
    return {
      loading: false,
      users: null,
      error: null,
    };
  },
  created() {
    this.fetchData();
  },
  methods: {
    fetchData() {
      this.error = this.users = null;
      this.loading = true;
      axios
        .get('/api/users')
        .then(response => {
          console.log(response);
        });
    }
  }
}
</script>

Если вы новичек в Vue или вам что-то не понятно в коде выше - не пугайтесь. Прочитайте документацию по компонентам Vue и вам все станет понятно.

В этом компоненте мы асинхронно загружаем данные во время инициализации компонента. Мы определили метод fetchData(), который устанавливает в null users и error переменные и устанавливает флаг (переменную) loading в true. Последняя строчка в fetchData() загружает данные с помощью Axios библиотеки, посылая запрос на наш Laravel API.

Если вы теперь откроете браузер и перейдете по адресу /users вы должны будете увидеть в консоли примерно следующее:

SPA with Laravel and Vue

Еще одна вещь на которую вам следует обратить внимание: использование "Разбора объекта":

<li v-for="{ name, email } in users">
  <strong>Name:</strong> {{ name }},
  <strong>Email:</strong> {{ email }}
</li>

 

С помощью "Разбора объекта" вы можете взять только нужные вам элементы из объекта, и откинуть все остальное.

Заканчиваем с Route компонентом

У нас уже есть маршрут и компонет которые обрабатывают /users URI. Давайте добавим ссылку для навигации в наш главный шаблон.

Откройте файл resources/assets/js/views/App.vue и добавьте ссылку:

<template>
  <div>
    <h1>Vue Router Demo App</h1>

    <p>
      <router-link :to="{ name: 'home' }">Home</router-link> |
      <router-link :to="{ name: 'hello' }">Hello World</router-link> |
      <router-link :to="{ name: 'users.index' }">Users</router-link>
    </p>

    <div class="container">
      <router-view></router-view>
    </div>
  </div>
</template>
<script>
  export default {}
</script>

Если вы теперь обновите страницу, вы должны увидеть следующее:

SPA with Laravel and Vue

Обработка ошибок

До этого момента наш компонент работал нормально, но что если API вернет нам ошибку? Давайте добавим симуляцию ошибки в наш API:

Route::get('/users', function () {
  if (rand(1, 10) < 3) {
    abort(500, 'We could not retrieve the users');
  }

  return factory('App\User', 10)->make();
});

Тут мы используем функцию rand() чтобы симулироваь случайную ошибку. Если вы сейчас несколько раз обновите страницу, вы должны будете увидеть ошибку в консоли:

Vue SPA with Laravel 5

Мы можем обработать эту ошибку с помощью метода catch():

fetchData() {
  this.error = this.users = null;
  this.loading = true;
  axios
    .get('/api/users')
    .then(response => {
      this.loading = false;
      this.users = response.data;
    }).catch(error => {
      this.loading = false;
      this.error = error.response.data.message || error.message;
    });
}

Тут мы устанавливаем переменную loading в false и записываем ошибку в переменную error.

Давайте добавим кнопку "Try Again", для улучшения юзабилити, при нажатии на которую будет вызываться метод fetchData():

<div v-if="error" class="error">
  <p>{{ error }}</p>

  <p>
    <button @click.prevent="fetchData">
      Try Again
    </button>
  </p>
</div>

Теперь, если вы будете обновлять страницу, вы должны будете увидеть нечто похожее при возникновении ошибки:

SPA with Laravel and Vue 6

Заключение

В этой короткой статье мы:

  • Добавили новый маршрут в Laravel, который возвращает фейковые данные
  • Добавили ссылку для навигации в App.vue
  • Научились делать асинхронные запросы после перехода по ссылке с помощью Axios
  • А так же научились обрабатывать HTTP ошибки с помощью Axios

В 3й части мы научимся загружать данные ДО того как будет совершен переход по ссылке.

Перевод статьи Building a Vue SPA with Laravel Part 2

Опубликовано:

Категории: Статьи