Индикатор хода загрузки файла с Axios и VueJS
Прошлая статья про загрузку файлов с помощью Axios и VueJS содержала базовый обзор того, как самостоятельно, без использования внешних компонентов, реализовать загрузку файлов с помощью Axios и VueJS.
Этот урок будет немного короче. Мы добавим индикатор прогресса загрузки файлов. В прошлой статье мы рассматривали различия между загрузкой одного и нескольких файлов. Однако, поскольку Axios отправляет запросы через XMLHttpRequest, он отправляет все файлы одновременно. Так что наш индикатор прогресса будет работать одинаково для одного или нескольких файлов.
Давайте начнем!
Создание компонента Vue
Сначала создадим наш компонент Vue. Для этого создадим новый файл FileProgress.vue со следующим содеражанием:
<template> </template> <script> export default { } </script>
Вы можете самостоятельно добавить тег style для стилей, если захотите (рекомендуется, для кода в продакшине, что бы приложение выглядело хорошо), но сейчас мы сделаем его максимально простым. Далее определим наш шаблон компонента.
Шаблон компонента
Теперь нам нужно добавить наш шаблон, поэтому добавим следующее в тег template:
<template> <div class="container"> <div class="large-12 medium-12 small-12 cell"> <label>File <input type="file" id="file" ref="file" v-on:change="handleFileUpload()"/> </label> <br> <progress max="100" :value.prop="uploadPercentage"></progress> <br> <button v-on:click="submitFile()">Submit</button> </div> </div> </template>
Есть пара вещей, на которые стоит обратить внимание. Наш input имеет атрибут ref=»file». Это позволяет сделать input доступным через локальную переменную $refs в нашем компоненте. Далее мы ожидаем, когда пользователь начнет загружать файл. В этот момент, мы копируем выбранный файл в локальную переменную file (которую мы добавим на следующем шаге), чтобы мы могли отправить его на сервер.
Самым важным элементом шаблона является элемент <progress>. Через него мы семантически отобразим ход загрузки файлов. Есть пара атрибутов, которые указывают на элемент. Первым является атрибут max. Мы установили его на 100, так как мы будем вычислять процент на основе 100.
Следующий атрибут в элементе <progress> — это атрибут :value.prop=»uploadPercentage». Поскольку элемент <progress> не является input, его значение является атрибутом, а не фактическим значением, которое имеет элемент input. Мы привязываем значение value в виде prop (с :value.prop) к вычисленному uploadPercentage. На следующем шаге мы добавим данные для uploadPercentage.
Последнее замечание о шаблоне — кнопка «Submit», при нажатии на которую запускается метод submitFile(). Это метод просто отправляет файл на сервер.
Добавим переменные в data
Добавим необходимые переменные используемые компонентом в метод data() компонента. Для этого добавим в свой компонент следующее:
data(){ return { file: '', uploadPercentage: 0 } },
Переменная file используется для хранения файла, загруженного пользователем. Параметр uploadPercentage по умолчанию равен 0 и будет заполнен процентом, загруженным через Axios.
Метод handleFileUpload()
Этот метод вызывается всякий раз, когда пользователь выбирает файл для загрузки. Просто добавьте это к объекту methods:
handleFileUpload(){ this.file = this.$refs.file.files[0]; }
Загружаемый файл передается в локальную переменную file, поэтому позже мы можем получить к нему доступ, когда отправим данные на сервер.
Метод submitFile()
Этот метод содержит ядро нашей функциональности. Он должен выглядеть следующим образом:
submitFile(){ let formData = new FormData(); formData.append('file', this.file); axios.post( '/file-progress', formData, { headers: { 'Content-Type': 'multipart/form-data' }, onUploadProgress: function(progressEvent) { this.uploadPercentage = parseInt(Math.round(( progressEvent.loaded / progressEvent.total) * 100); }.bind(this) } ).then(function(){ console.log('SUCCESS!!'); }) .catch(function(){ console.log('FAILURE!!'); }); },
Сначала мы инициализируем экземпляр объекта FormData():
let formData = new FormData();
Это позволит добавить данные для нашего файла к данным, передаваемым в форму, следующим образом:
formData.append('file', this.file);
Теперь у нас есть файл, добавленный в объект данных формы. Следующая функция — это то, как мы вычисляем ход загрузки, и с помощью этого метода мы делаем только один индикатор выполнения, поэтому нам нужно только получить ход процесса загрузки.
Следующий код загружает файл на сервер:
axios.post( '/file-progress', formData, { headers: { 'Content-Type': 'multipart/form-data' }, onUploadProgress: function(progressEvent) { this.uploadPercentage = parseInt(Math.round(( progressEvent.loaded / progressEvent.total) * 100); }.bind(this) } ).then(function(){ console.log('SUCCESS!!'); }) .catch(function(){ console.log('FAILURE!!'); });
Мы отправляем данные в конечную точку /file-progress. Затем мы передаем formData в качестве второго параметра, который является параметром данных. Третий параметр — это наша конфигурация. Здесь мы добавляем наш заголовок для ‘Content-Type’: ‘multipart/form-data’, чтобы сервер знал, что мы можем прикрепить файлы.
Затем мы добавляем метод, который присоединяется к событию onUploadProgress. Вложенный метод содержит progressEvent в качестве параметра. Мы можем использовать этот параметр, чтобы определить, как далеко мы продвинулись в загрузке файлов. Во-первых, мы должны связать this с методом, чтобы иметь доступ к локальным переменным нашего компонента. Затем мы вычисляем процент загрузки, беря то, что было загружено, умножая его на 100, чтобы адаптировать его в процентный формат, а затем делим его на общее количество файлов для загрузки, чтобы получить процент:
this.uploadPercentage = parseInt( Math.round( ( progressEvent.loaded / progressEvent.total ) * 100 );
Так как мы передали его в uploadPercentage, VueJS установит наш индикатор выполнения для представления статуса. Это все, что нам действительно нужно, чтобы показать прогресс! Конечно, вы можете использовать и другие элементы и использовать вычисленный процент, чтобы показать отображение, но элемент <progress> является семантическим и может быть стилизован под ваши нужды.
На данный момент у меня просто есть listener успешного запроса, и catch который улавливает все неудачные запросы и выводит статус в консоль.
Заключение
Эта небольшая настройка UX может значительно улучшить интерфейс ваших пользователей, показывая им, как далеко продвигается процесс загрузки файлов. Это особенно полезно при создании одностраничного приложения или приложения на основе API.
Оригинальная статья: Dan Pastori — File Upload Progress Indicator with Axios and VueJS