Индикатор выполнения - это строка, показывающая, насколько близко к завершению что-то в приложении с графическим интерфейсом. Он обеспечивает удобство работы пользователей, потому что они могут знать, когда что-то завершено и насколько близко к завершению, что делает умы пользователей более комфортными.
Для Vue.js создано множество библиотек индикаторов выполнения. Один из них - Vue-ProgressBar, расположенный по адресу https://github.com/hilongjw/vue-progressbar. Его легко включить в любое приложение Vue.js, и он очень гибкий, с множеством опций, которые вы можете изменить.
В этой статье мы создадим приложение, которое отображает шутки Чака Норриса из API шуток Чака Норриса, расположенного по адресу https://api.chucknorris.io/. Приложение будет иметь домашнюю страницу для отображения случайной шутки, страницу, которая позволяет пользователям искать случайную шутку по категориям, и страницу поиска для поиска шуток. Для начала запустим Vue CLI, запустив:
npx @vue/cli create chuck-norris-app
В мастере выбираем «Выбрать функции вручную» и выбираем Vue Router и Babel.
Далее мы устанавливаем несколько пакетов. Мы будем использовать Axios для выполнения HTTP-запросов, BootstrapVue для стилизации, Vue-ProgressBar для добавления индикатора выполнения и Vee-Validate для проверки формы. Для их установки запускаем:
npm i axios bootstrap-vue vue-progressbar vee-validate
Затем мы создаем папкуmixins
в папке src
и создаем файл с именем requestsMixin.js
file. Там мы добавляем:
const APIURL = "https://api.chucknorris.io/jokes"; const axios = require("axios"); export const requestsMixin = { methods: { getRandomJoke() { return axios.get(`${APIURL}/random`); }, getJokeByCategory(category) { return axios.get(`${APIURL}/random?category=${category}`); }, getCategories() { return axios.get(`${APIURL}/categories`); }, searchJokes(query) { return axios.get(`${APIURL}/search?query=${query}`); } } };
В этом файле содержится код для вызова всех конечных точек API-интерфейса Чака Норриса для получения шуток и категорий, а также для поиска шуток по ключевым словам.
Затем в папке views
мы заменяем код в файле Home.vue
на:
<template> <div class="page"> <h1 class="text-center">Random Joke</h1> <p>{{joke.value}}</p> </div> </template> <script> import { requestsMixin } from "@/mixins/requestsMixin"; export default { name: "home", mixins: [requestsMixin], data() { return { joke: {} }; }, beforeMount() { this.$Progress.start(); this.getJoke(); }, methods: { async getJoke() { const { data } = await this.getRandomJoke(); this.joke = data; this.$Progress.finish(); } } }; </script>
С библиотекой Vue-ProgressBar у нас есть объект this.$Progress
, доступный во всех наших компонентах, поскольку мы добавим его в main.js
. Мы вызываем this.$Progress.start();
для отображения индикатора выполнения прямо перед выполнением HTTP-запроса, вызывая функцию this.getRandomJoke
из requestsMixin
. Затем, как только ответ будет успешно получен, мы вызываем this.$Progress.finish();
, чтобы индикатор выполнения исчез. В шаблоне отображаем анекдот.
Затем создайте файл с именемJokeByCategory.vue
в папке views
и добавьте:
<template> <div class="page"> <h1 class="text-center">Joke by Category</h1> <ValidationObserver ref="observer" v-slot="{ invalid }"> <b-form novalidate> <b-form-group label="Category"> <ValidationProvider name="category" rules="required" v-slot="{ errors }"> <b-form-select v-model="category" :options="categories" @change="getJoke()"></b-form-select> <b-form-invalid-feedback :state="errors.length == 0">{{errors.join('. ')}}</b-form-invalid-feedback> </ValidationProvider> </b-form-group> </b-form> </ValidationObserver> <p>{{joke.value}}</p> </div> </template> <script> import { requestsMixin } from "@/mixins/requestsMixin"; export default { mixins: [requestsMixin], data() { return { category: "", categories: [], joke: {} }; }, beforeMount() { this.getJokeCategories(); }, methods: { async getJokeCategories() { this.$Progress.start(); const { data } = await this.getCategories(); this.categories = data.map(d => ({ value: d, text: d })); this.$Progress.finish(); }, async getJoke() { this.$Progress.start(); const isValid = await this.$refs.observer.validate(); if (!isValid) { this.$Progress.finish(); return; } const { data } = await this.getJokeByCategory(this.category); this.joke = data; this.$Progress.finish(); } } }; </script>
В ловушке beforeMount
мы запускаем getJokeCategories
, который вызывает this.getCategories
из requestsMixin
, чтобы получить категории при загрузке страницы.
Эта страница работает так же, как Home.vue
. Мы отображаем индикатор выполнения при запуске запросов и удаляем его, когда запрос завершен. Этот файл выполняет 2 запроса: один для получения категорий из API с функцией this.categories
из requestsMixin
и функцией this.getJokesByCategory
из того же файла.
В функции getJoke
мы проверяем нашу форму с помощью Vee-Validate, вызывая this.$refs.observer.validate();
, чтобы убедиться, что category
выбрано, прежде чем получить шутку.
Мы используем Vee-Validate для проверки полей формы. Компонент ValidationObserver
предназначен для проверки всей формы, а компонент ValidationProvider
- для проверки полей формы, которые он обтекает.
Правило проверки определяется свойством rule
поля category
. Параметр state
предназначен для установки состояния проверки, которое показывает зеленый цвет, когда errors
имеет длину 0, и красный цвет в противном случае.
Сообщения об ошибках отображаются в компоненте b-form-invalid-feedback
. На этой странице есть только раскрывающийся список стран.
Затем мы добавляем файл Search.vue
в папку views
и добавляем:
<template> <div class="page"> <h1 class="text-center">Search</h1> <ValidationObserver ref="observer" v-slot="{ invalid }"> <b-form novalidate @submit.prevent="onSubmit"> <b-form-group label="Keyword"> <ValidationProvider name="keyword" rules="required" v-slot="{ errors }"> <b-form-input type="text" :state="errors.length == 0" v-model="keyword" required placeholder="Search " name="keyword" ></b-form-input> <b-form-invalid-feedback :state="errors.length == 0">{{errors.join('. ')}}</b-form-invalid-feedback> </ValidationProvider> </b-form-group> <b-button type="submit" variant="primary">Search</b-button> </b-form> </ValidationObserver> <p v-for="(j, i) of jokes" :key="i">{{j.value}}</p> </div> </template> <script> import { requestsMixin } from "@/mixins/requestsMixin"; export default { mixins: [requestsMixin], data() { return { keyword: "", jokes: [] }; }, methods: { async onSubmit() { this.$Progress.start(); const isValid = await this.$refs.observer.validate(); if (!isValid) { this.$Progress.finish(); return; } const { data: { result } } = await this.searchJokes(this.keyword); this.jokes = result; this.$Progress.finish(); } } }; </script>
Мы позволяем пользователям искать анекдоты в API.
В функции onSubmit
мы проверяем нашу форму с помощью Vee-Validate, вызывая this.$refs.observer.validate();
, чтобы убедиться, что category
выбрано, прежде чем получить шутку. Мы используем Vee-Validate для проверки полей формы. Компонент ValidationObserver
предназначен для проверки всей формы, а компонент ValidationProvider
предназначен для проверки полей формы, которые он обтекает. Правило проверки определяется опцией rule
поля category
. Параметр state
предназначен для установки состояния проверки, которое показывает зеленый цвет, когда errors
имеет длину 0, и красный цвет в противном случае. Сообщения об ошибках отображаются в компоненте b-form-invalid-feedback
. На этой странице есть только раскрывающийся список стран.
Индикатор выполнения работает так же, как и другие компоненты. Мы отображаем индикатор выполнения при поиске шуток, вызывая this.$Progress.start();
, затем this.searchJokes
и удаляем его, когда запрос завершен. Наконец, вызывается this.$Progress.finish();
, чтобы индикатор выполнения исчез.
Затем в App.vue
мы заменяем существующий код на:
<template> <div id="app"> <vue-progress-bar></vue-progress-bar> <b-navbar toggleable="lg" type="dark" variant="info"> <b-navbar-brand to="/">Chuck Norris Jokes App</b-navbar-brand> <b-navbar-toggle target="nav-collapse"></b-navbar-toggle> <b-collapse id="nav-collapse" is-nav> <b-navbar-nav> <b-nav-item to="/" :active="path == '/'">Home</b-nav-item> <b-nav-item to="/jokebycategory" :active="path == '/jokebycategory'">Jokes By Category</b-nav-item> <b-nav-item to="/search" :active="path == '/search'">Search</b-nav-item> </b-navbar-nav> </b-collapse> </b-navbar> <router-view /> </div> </template> <script> export default { data() { return { path: this.$route && this.$route.path }; }, watch: { $route(route) { this.path = route.path; } } }; </script> <style lang="scss"> .page { padding: 20px; } button, .btn.btn-primary { margin-right: 10px !important; } .button-toolbar { margin-bottom: 10px; } </style>
чтобы добавить панель навигации Bootstrap в верхнюю часть наших страниц и router-view
для отображения определяемых нами маршрутов.
Затем в main.js
замените код на:
import Vue from "vue"; import App from "./App.vue"; import router from "./router"; import store from "./store"; import BootstrapVue from "bootstrap-vue"; import "bootstrap/dist/css/bootstrap.css"; import "bootstrap-vue/dist/bootstrap-vue.css"; import { ValidationProvider, extend, ValidationObserver } from "vee-validate"; import { required } from "vee-validate/dist/rules"; import VueProgressBar from "vue-progressbar"; extend("required", required); Vue.component("ValidationProvider", ValidationProvider); Vue.component("ValidationObserver", ValidationObserver); Vue.use(BootstrapVue); Vue.use(VueProgressBar, { color: "rgb(143, 255, 199)", failedColor: "red", height: "2px" }); Vue.config.productionTip = false; new Vue({ router, store, render: h => h(App) }).$mount("#app");
так что мы добавляем библиотеки, которые мы установили в наше приложение, чтобы мы могли использовать их в наших компонентах. Мы вызываем extend
из Vee-Validate, чтобы добавить правила проверки формы, которые мы хотим использовать. Кроме того, мы добавляем сюда библиотеку Vue-ProgressBar, чтобы мы могли использовать ее во всех наших компонентах. Когда мы включаем его с Vue.use
, мы передаем параметры индикатора выполнения в качестве второго аргумента. В этом приложении мы устанавливаем зеленоватый цвет, неудачный цвет - красный, а высоту - 2 пикселя. Мы также импортировали CSS Bootstrap в этот файл, чтобы получить стили.
В router.js
мы заменяем существующий код на:
import Vue from 'vue' import Router from 'vue-router' import Home from './views/Home.vue' import JokeByCategory from './views/JokeByCategory.vue' import Search from './views/Search.vue' Vue.use(Router) export default new Router({ mode: 'history', base: process.env.BASE_URL, routes: [ { path: '/', name: 'home', component: Home }, { path: '/jokebycategory', name: 'jokebycategory', component: JokeByCategory }, { path: '/search', name: 'search', component: Search } ] })
чтобы включить нашу домашнюю страницу и страницу поиска.
Наконец, в index.html
замените существующий код на:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width,initial-scale=1.0" /> <link rel="icon" href="<%= BASE_URL %>favicon.ico" /> <title>Chuck Norris Jokes App</title> </head> <body> <noscript> <strong >We're sorry but vue-progress-bar-tutorial-app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong > </noscript> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
изменить название.
После всей тяжелой работы мы можем запустить наше приложение, запустив npm run serve
. В итоге получаем: