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

Один из способов использования фиктивных данных - просто добавить их непосредственно в компоненты Vue или в магазин Vuex. Но это затрудняет переключение на реальные данные, когда API готов к использованию.

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

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

Теперь мы знаем, зачем нам нужны фиктивные данные в нашем приложении Vue, давайте погрузимся в подробности и узнаем, как это сделать.

Примечание: в этом руководстве предполагается, что вы знакомы с Vuex.

Настройка проекта

Давайте быстро создадим новый проект с Vue CLI. Обратите внимание, что здесь мы используем Vue CLI 3. Поэтому убедитесь, что он установлен, прежде чем запускать следующую команду.

vue create vue-mock-data

Эта команда должна отображать доступные типы проектов. В нашем примере выберите ‌typical-spa.

В нашем примере у нас будет список заголовков сообщений, хранящихся во Vuex. Мы начнем с добавления кучи фиктивных сообщений непосредственно в объект состояния. А позже мы переместим их в место, предназначенное для фиктивных данных.

Так что добавьте эти заголовки сообщений в src/store.js:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
  state: {
    posts: [
      { title: 'Post Title 1' },
      { title: 'Post Title 2' },
      { title: 'Post Title 3' },
      { title: 'Post Title 4' },
      { title: 'Post Title 5' }
    ]
  },
  mutations: {},
  actions: {}
})

Отображение сообщений

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

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

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

Итак, давайте обновим src/views/Home.vue, чтобы он стал таким:

<template>
  <div class="home">
    <ul class="posts">
      <li
        v-for="post in posts"
        :key="post.title"
        class="post-item"
      >
          <h1>{{ post.title }}</h1>
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  computed: {
    posts () {
      return this.$store.state.posts
    }
  }
}
</script>
<style scoped>
.posts {
  list-style: none;
  text-align: left;
}
.post-item + .post-item {
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}
</style>

Если вы проверите браузер, вы увидите, что все сообщения отображаются следующим образом:

Использование клиента динамического API

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

Поскольку оба источника (клиенты api) реализуют одни и те же методы api, мы можем написать код выборки только один раз без каких-либо условий или около того - это, кстати, называется кодированием интерфейса.

Давайте напишем этот код загрузки внутри store.js.

import Vue from 'vue'
import Vuex from 'vuex'
import client from 'api-client'
Vue.use(Vuex)
export default new Vuex.Store({
  state: {
    posts: []
  },
  mutations: {
    setPosts (state, posts) {
      state.posts = posts
    }
  },
  actions: {
    fetchPosts ({ commit }) {
      return client
        .fetchPosts()
        .then(posts => commit('setPosts', posts))
    }
  }
})

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

Итак, все это оставляет нам две вещи:

  1. Реализуйте эти два клиента api - один для реальных данных, а другой для фиктивных данных.
  2. Реализуйте параметр конфигурации, который определяет, какой клиент api использовать.

Реализация обоих клиентов api

Нашим текущим шагом является реализация обоих клиентов api, которые мы собираемся динамически разрешать как модуль api-client. У нас будет все, что связано с нашим api, в новом каталоге: src/api. В этом каталоге создайте еще два подкаталога, один называется mock, а другой - server. Затем в каждый из них добавьте новый файл index.js.

Теперь давайте сначала реализуем макет клиента api. Но перед этим давайте создадим новый каталог внутри src/api/mock, чтобы все наши фиктивные данные хранились в файлах JSON. Назовем этот каталог data.

Давайте создадим наш первый файл фиктивных данных внутри src/api/mock/data/, назовем его posts.json, а затем поместим в него следующее:

[
  { "title": "Post Title 1" },
  { "title": "Post Title 2" },
  { "title": "Post Title 3" },
  { "title": "Post Title 4" },
  { "title": "Post Title 5" }
]

Чтобы убедиться, что мы находимся на одной странице, вот как должен выглядеть ваш api каталог:

api
├── mock
│   ├── data
│   │   └── posts.json
│   └── index.js
└── server
    └── index.js

Пришло время реализовать наш макет api-клиента в mock/index.js:

import posts from './data/posts'
const fetch = (mockData, time = 0) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(mockData)
    }, time)
  })
}
export default {
  fetchPosts () {
    return fetch(posts, 1000) // wait 1s before returning posts
  }
}

Основное, что делает этот файл, - это экспорт объекта с методом получения сообщений. Но обратите внимание, что этот метод должен называться fetchPosts, потому что это то, что мы использовали в store.js, помните? Кроме того, я создал вспомогательную функцию для имитации выборки данных. Эта функция также дает нам возможность указать, сколько времени потребуется для получения данных - это было бы полезно для отображения индикаторов загрузки.

Теперь макет api-клиента готов, давайте реализуем серверный api-клиент. Поместите в src/api/server/index.js следующее:

import axios from 'axios'
export default {
  fetchPosts () {
    return axios
      .get('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.data)
  }
}

Как и в случае с mock-клиентом api, мы экспортируем объект с помощью метода fetchPosts. В этом методе мы получаем сообщения из поддельного API.

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

npm install axios --save

Реализация резолвера api-client

Webpack предоставляет нам способ определить, как разрешить конкретный модуль, когда мы импортируем его с синтаксисом import. Эта функция называется Решить.

В Vue CLI 3 мы можем связать конфигурации Webpack с функцией chainWebpack. И в этой функции мы можем добавить правило разрешения, которое разрешает api-client в src/api/mock/index.js или src/api/server/index.js.

Вы можете думать о разрешении модуля просто как о замене пути к импортированному модулю (в данном случае это api-client) любым путем, который мы хотим.

Мы определяем наши конфигурации vue в файле vue.config.js. Итак, создайте его в корневом каталоге вашего проекта и поместите в него:

const path = require('path')
module.exports = {
  chainWebpack: config => {
    const apiClient = process.env.VUE_APP_API_CLIENT // mock or server
    config.resolve.alias.set(
      'api-client',
      path.resolve(__dirname, `src/api/${apiClient}`)
    )
  }
}

Как видно из приведенного выше кода, мы преобразовываем api-client в src/api/${apiClient}, где apiClient - это то, что мы получаем из переменных среды.

Вы можете узнать больше о переменных окружения в документации по Vue CLI 3.

В нашем примере мы собираемся определить два файла env для производственного режима и режима разработки. В среде разработки мы собираемся установить клиент api на mock, но для производства мы собираемся установить его на server.

Итак, создайте .env.development и .env.production в корне вашего проекта. Затем поместите это в .env.development:

VUE_APP_API_CLIENT = 'mock'

И это в .env.production:

VUE_APP_API_CLIENT = 'server'

Обновление главной страницы

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

В конечном итоге ваш Home.vue должен выглядеть так:

<template>
  <div class="home">
    <span v-if="loading">Loading…</span>
    <ul
      v-else
      class="posts"
    >
      <li
        v-for="post in posts"
        :key="post.title"
        class="post-item"
      >
          <h1>{{ post.title }}</h1>
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  data () {
    return {
      loading: false
    }
  },
  computed: {
    posts () {
      return this.$store.state.posts
    }
  },
  created () {
    this.loading = true
    this.$store.dispatch('fetchPosts')
      .then(posts => {
        this.loading = false
      })
  }
}
</script>
<style scoped>
.posts {
  list-style: none;
  text-align: left;
}
.post-item + .post-item {
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}
</style> 

Теперь вы можете наконец проверить свою работу, изменив VUE_APP_API_CLIENT в целевой среде на mock или server. Но учтите, что каждый раз, когда вы его меняете, вам нужно перезапускать / пересобирать приложение.

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

Примечание. Вы можете получить исходный код этого руководства на GitHub.

📝 Прочтите этот рассказ позже в Журнале.

🗞 Просыпайтесь каждое воскресное утро и слышите самые интересные истории, мнения и новости недели, ожидающие в вашем почтовом ящике: Получите примечательный информационный бюллетень›