Статьи

Извлечение данных из стороннего API с помощью Vue.js и Axios

Хотите узнать Vue.js с нуля? Получите полную коллекцию книг Vue, охватывающих основы, проекты, советы и инструменты и многое другое с SitePoint Premium. Присоединяйтесь сейчас всего за $ 14,99 / месяц .

Чаще всего при создании приложения JavaScript вам нужно будет получать данные из удаленного источника или использовать API . Недавно я изучил некоторые общедоступные API и обнаружил, что с этими источниками можно сделать много интересных вещей.

Женщина собирает данные с библиотечных полок

С помощью Vue.js вы можете буквально создать приложение на основе одного из этих сервисов и начать предоставлять контент пользователям за считанные минуты.

Я покажу, как создать простое новостное приложение, которое будет показывать самые популярные новостные статьи дня, позволяя пользователям фильтровать по категориям интересов, получая данные из API New York Times . Вы можете найти полный код этого урока здесь .

Вот как будет выглядеть финальное приложение:

Веб-приложение новостей Vue.js

Чтобы следовать этому уроку, вам понадобятся базовые знания Vue.js. Вы можете найти отличное руководство по началу работы для этого здесь . Я также буду использовать синтаксис ES6, и вы можете узнать об этом здесь .

Структура проекта

Мы сделаем все очень просто, ограничившись двумя файлами:

./app.js
./index.html

app.jsindex.html

Мы начнем с некоторой базовой разметки в index.html

 <!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>The greatest news app ever</title>
  </head>
  <body>
    <div class="container" id="app">
      <h3 class="text-center">VueNews</h3>
    </div>
  </body>
</html>

Затем включите Vue.js и app.jsindex.html</body>

 <script src="https://unpkg.com/vue"></script>
<script src="app.js"></script>

При желании можно включить Foundation , чтобы воспользоваться некоторыми готовыми стилями и сделать наш взгляд более привлекательным. Включите это в <head>

 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css">

Создание простого приложения Vue

Сначала мы создадим новый экземпляр Vue в элементе div#app

 // ./app.js
const vm = new Vue({
  el: '#app',
  data: {
    results: [
      {title: "the very first post", abstract: "lorem ipsum some test dimpsum"},
      {title: "and then there was the second", abstract: "lorem ipsum some test dimsum"},
      {title: "third time's a charm", abstract: "lorem ipsum some test dimsum"},
      {title: "four the last time", abstract: "lorem ipsum some test dimsum"}
    ]
  }
});

Мы сообщаем Vue, на какой элемент монтировать, с помощью опции el , и определяем, какие данные будет использовать наше приложение с помощью опции data .

Чтобы отобразить эти фиктивные данные в нашем представлении приложения, мы можем написать эту разметку внутри элемента #app

 <!-- ./index.html -->
<div class="columns medium-3" v-for="result in results">
  <div class="card">
    <div class="card-divider">
      {{ result.title }}
    </div>
    <div class="card-section">
      <p>{{ result.abstract }}.</p>
    </div>
  </div>
</div>

Директива v-for Мы также используем двойные фигурные скобки, чтобы показать содержимое каждого из них.

Примечание: вы можете прочитать больше о синтаксисе шаблона Vue здесь .

Теперь у нас есть основной рабочий макет:

Простое новостное приложение с фиктивными данными

Извлечение данных из API

Чтобы использовать API NYTimes, вам нужно получить ключ API. Так что, если у вас его еще нет, зайдите на их страницу регистрации и зарегистрируйтесь, чтобы получить ключ API для API Top Stories .

Создание Ajax-запросов и обработка ответов

Axios — это HTTP-клиент на основе обещаний для выполнения Ajax-запросов, который отлично подойдет для наших целей. Он предоставляет простой и богатый API. Это очень похоже на API fetchтонкости .

Примечание. Раньше vue-resourceтеперь он удален .

Включая аксиосы:

 <!-- ./index.html -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

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

 // ./app.js

const vm = new Vue({
  el: '#app',
  data: {
    results: []
  },
  mounted() {
    axios.get("https://api.nytimes.com/svc/topstories/v2/home.json?api-key=your_api_key")
    .then(response => {this.results = response.data.results})
  }
});

Помните: замените your_api_keyNYT Dev Network .

Теперь мы можем видеть новостную ленту на главной странице нашего приложения. Не беспокойтесь о искаженном виде; мы вернемся к этому чуть позже:

Новостная лента

Ответ от NYT API выглядит следующим образом через Vue devtools:

Ответ от NYT API - новостное приложение Vue.js

Совет: используйте Vue Devtools, чтобы упростить отладку приложений Vue.

Чтобы сделать нашу работу более аккуратной и многократно используемой, мы проведем небольшой рефакторинг и представим вспомогательную функцию для построения наших URL-адресов. Мы также зарегистрируем getPostsобъекту methods :

 const NYTBaseUrl = "https://api.nytimes.com/svc/topstories/v2/";
const ApiKey = "your_api_key";

function buildUrl (url) {
  return NYTBaseUrl + url + ".json?api-key=" + ApiKey
}

const vm = new Vue({
  el: '#app',
  data: {
    results: []
  },
  mounted () {
    this.getPosts('home');
  },
  methods: {
    getPosts(section) {
      let url = buildUrl(section);
      axios.get(url).then((response) => {
        this.results = response.data.results;
      }).catch( error => { console.log(error); });
    }
  }
});

Мы можем внести еще некоторые изменения в то, как выглядит наше представление, введя вычисляемое свойство с некоторыми изменениями исходных результатов, возвращаемых из API:

 // ./app.js

const vm = new Vue({
  el: '#app',
  data: {
    results: []
  },
  mounted () {
    this.getPosts('home');
  },
  methods: {
    getPosts(section) {
      let url = buildUrl(section);
      axios.get(url).then((response) => {
        this.results = response.data.results;
      }).catch( error => { console.log(error); });
    }
  },
  computed: {
    processedPosts() {
      let posts = this.results;

      // Add image_url attribute
      posts.map(post => {
        let imgObj = post.multimedia.find(media => media.format === "superJumbo");
        post.image_url = imgObj ? imgObj.url : "http://placehold.it/300x200?text=N/A";
      });

      // Put Array into Chunks
      let i, j, chunkedArray = [], chunk = 4;
      for (i=0, j=0; i < posts.length; i += chunk, j++) {
        chunkedArray[j] = posts.slice(i,i+chunk);
      }
      return chunkedArray;
    }
  }
});

В приведенном выше коде в вычисляемом свойстве processedPostsimage_url Мы делаем это, просматривая resultsmultimedia Затем мы назначаем URL этого носителя image_url В тех случаях, когда носитель недоступен, мы делаем URL-адрес по умолчанию изображением из Placehold.it .

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

Примечание: Вы также можете легко сделать это с библиотекой вроде Lodash .

Вычисленные свойства отлично подходят для манипулирования данными. Вместо того, чтобы создавать метод и вызывать его каждый раз, когда нам нужно разделить наш массив сообщений, мы можем просто определить его как вычисляемое свойство и использовать его по своему желанию, поскольку Vue автоматически обновляет вычисляемое свойство processingPosts при processedPostsresults

Вычисляемые свойства также кэшируются на основе их зависимостей, поэтому до тех пор, пока results Это поможет с производительностью, особенно при выполнении сложных манипуляций с данными.

Затем мы редактируем нашу разметку в processedPosts

 index.html

Теперь приложение выглядит немного лучше:

NYT News App - Vue.js

Представление компонента списка новостей

Компоненты могут использоваться для поддержания модульности приложения и в основном расширять HTML. «Список новостей» может быть реорганизован для компонента, так что, например, если приложение расширяется и принимается решение использовать список новостей где-либо еще, это будет легко:

 <!-- ./index.html -->
<div class="row" v-for="posts in processedPosts">
  <div class="columns large-3 medium-6" v-for="post in posts">
    <div class="card">
    <div class="card-divider">
      {{ post.title }}
    </div>
    <a :href="post.url" target="_blank"><img :src="post.image_url"></a>
    <div class="card-section">
      <p>{{ post.abstract }}</p>
    </div>
  </div>
  </div>
</div>

В приведенном выше коде мы регистрируем глобальный компонент, используя синтаксис // ./app.js

Vue.component(‘news-list’, {
props: [‘results’],
template: `
<section>
<div class=»row» v-for=»posts in processedPosts»>
<div class=»columns large-3 medium-6″ v-for=»post in posts»>
<div class=»card»>
<div class=»card-divider»>
{{ post.title }}
</div>
<a :href=»post.url» target=»_blank»><img :src=»post.image_url»></a>
<div class=»card-section»>
<p>{{ post.abstract }}</p>
</div>
</div>
</div>
</div>
</section>
`
,
computed: {
processedPosts() {
let posts = this.results;

// Add image_url attribute
posts.map(post => {
let imgObj = post.multimedia.find(media => media.format === «superJumbo»);
post.image_url = imgObj ? imgObj.url : «http://placehold.it/300×200?text=N/A»;
});

// Put Array into Chunks
let i, j, chunkedArray = [], chunk = 4;
for (i=0, j=0; i < posts.length; i += chunk, j++) {
chunkedArray[j] = posts.slice(i,i+chunk);
}
return chunkedArray;
}
}
});

const vm = new Vue({
el: ‘#app’,
data: {
results: []
},
mounted () {
this.getPosts(‘home’);
},
methods: {
getPosts(section) {
let url = buildUrl(section);
axios.get(url).then((response) => {
this.results = response.data.results;
}).catch( error => { console.log(error); });
}
}
});
Рекомендуется использовать дефис при определении имен тегов, чтобы они не конфликтовали с текущими или будущими стандартными тегами HTML.

Введенные нами дополнительные параметры объясняются следующим образом.

  • Реквизиты : это массив данных, которые мы хотим передать компоненту из родительской области. Мы добавили Vue.component(tagName, options)
  • Шаблон : здесь мы определяем разметку для списка новостей. Обратите внимание, что мы завернули наш список в results Это потому, что компонент должен иметь один корневой элемент, а не несколько (который был бы создан нашей итерацией <section>

Настройка нашей разметки для использования нашего компонента div.rownews-list

 results

Примечание. Компоненты также можно создавать как отдельные файловые компоненты (файлы <!-- ./index.html -->

<div class=«container« id=«app«>
<h3 class=«text-center«>VueNews</h3>
<news-list :results=«results«></news-list>
</div>
веб-пакет . Хотя это выходит за рамки этого учебного пособия, оно рекомендуется для более крупных или более сложных приложений.

Чтобы продвинуться дальше, вы могли бы даже пойти дальше, сделав каждую статью компонентом, и сделать вещи еще более модульными.

Реализация фильтров категории

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

Сначала мы зарегистрируем список разделов и раздел, который просматривается в нашем приложении:

 .vue

Далее мы можем добавить это в наш контейнер const SECTIONS = "home, arts, automobiles, books, business, fashion, food, health, insider, magazine, movies, national, nyregion, obituaries, opinion, politics, realestate, science, sports, sundayreview, technology, theater, tmagazine, travel, upshot, world"; // From NYTimes

const vm = new Vue({
el: ‘#app’,
data: {
results: [],
sections: SECTIONS.split(‘, ‘), // create an array of the sections
section: ‘home’, // set default section to ‘home’
},
mounted () {
this.getPosts(this.section);
},
// ….
});

 div#app

При нажатии кнопки «Получить» мы <!-- ./index.html -->
<section class="callout secondary">
<h5 class="text-center">Filter by Category</h5>
<form>
<div class="row">
<div class="large-6 columns">
<select v-model="section">
<option v-for="section in sections" :value="section">{{ section }}</option>
</select>
</div>
<div class="medium-6 columns">
<a @click="getPosts(section)" class="button expanded">Retrieve</a>
</div>
</div>
</form>
</section>
getPostsclick@click

Последние штрихи и демонстрации

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

Вы можете увидеть демо в CodePen ниже (ограниченная функциональность):

Кроме того, вы можете просмотреть живую версию здесь .

Вывод

В этом руководстве мы узнали, как запустить проект Vue.js с нуля, как извлекать данные из API, используя axios , и как обрабатывать ответы и манипулировать данными с использованием компонентов и вычисляемых свойств.

Теперь у нас есть функциональное приложение Vue.js 2.0, построенное на основе API-сервиса. Есть множество улучшений, которые можно сделать, подключив некоторые другие API. Например, мы могли бы:

  • автоматически ставить посты в социальных сетях из категории с помощью Buffer API
  • Пометить сообщения, которые будут прочитаны позже, используя Pocket API

… и так далее.

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