Я работаю над проектом, который позволит учителям загружать и скачивать планы уроков (файлы), чтобы они могли делиться своими знаниями и опытом. Для учителей эти типы файлов чаще всего представляют собой файлы .doc или .pdf или, возможно, даже .ppt, если они представляют презентацию своим ученикам. Предпочтением для этого приложения будут файлы .doc, поскольку учителя смогут загружать вложения и вносить изменения напрямую. Это позволит им легко адаптировать уроки к своим классам и ученикам. Тем не менее, любой тип файла может быть загружен.

Итак, начнем!

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

«Название урока», раскрывающийся список «Оценка» и раскрывающийся список «Тема» выводят все строки сообщений на серверную часть Rails, настроенную как API. «Описание урока» также публикуется в той же серверной части, но в виде текста, а не строки, чтобы можно было публиковать более длинный фрагмент текста.

Теперь к опции «Выбрать файл».

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

Просто для ясности я использую Atom в качестве текстового редактора. Это приложение также построено с использованием JavaScript, в основном React, поэтому приведенный выше код — это JSX. Теперь, когда это не так, это ‹div› в полной ‹form›. Что касается ввода, ‹div› и ‹i› с classNames можно игнорировать, поскольку их цель здесь — служить стилем страницы. Основная часть, на которой следует сосредоточиться, — это «ввод», в частности тип.

Входные данные могут быть разных типов, и когда я начал программировать, в первую очередь это был тип «текст». Затем я стал более изобретательным и стал использовать ‹textarea› или даже ‹select› с многочисленными ‹options› вместо простого старого ‹input›. Но чтобы получить наш файл, все, что нам нужно, это старый добрый ‹input› с типом «файл». Это предоставит вам нужное поле, то, что в моей форме на первом изображении выше. Это так просто!

Когда данные добавляются в форму, независимо от ввода, функция onChange обрабатывает вводимые данные, сохраняя их в локальном состоянии этого компонента, как показано ниже.

Когда пользователь нажимает кнопку «Отправить урок», информация, хранящаяся в указанном выше состоянии, — это то, что будет отправлено в API Rails. Было немного сложно обрабатывать изменения как ввода файла, так и всего остального. Я все еще мог сделать это, используя условное выражение, как показано ниже. Это handleChange, который используется всеми моими полями ввода.

Вышеприведенное может показаться немного запутанным, особенно часть event.target.files[0]. При сохранении файла большое количество информации отправляется как часть event.target.files, представляющего собой массив. Нам нужен сам файл, который является первым элементом этого массива, следовательно, [0]. Как вы можете видеть выше, у меня есть привычка console.log регистрировать свои значения, чтобы точно узнать, что было получено.

Итак, мы преодолели два основных препятствия!

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

‹ввод› тип = «файл»

Проверять!

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

Проверять!

Но то, что у нас есть, не может быть действительно отправлено в том виде, в котором оно существует в настоящее время. Если бы мы прямо сейчас нажали «Отправить урок», то получили бы ошибку. Причина этого в том, что это приложение будет отправлять JSON в API, а это означает, что все данные должны быть преобразованы в строки. Однако файл, который у нас есть прямо сейчас, не является строкой. Здесь на помощь приходит Base64.

Итак, давайте рассмотрим отправку.

Вот onSubmit, который вызывает следующую функцию handleSubmit.

Нажатие «Отправить урок» первоначально сделает следующие две вещи. Во-первых, он установит состояние fileName в this.state.file.name. Это фактическое имя выбранного нами файла, который мы будем публиковать в нашем API. Позже вы увидите, зачем нам нужно имя файла.*

Во-вторых, после запуска функции setState она вызывает анонимный обратный вызов, который вызывает функцию convertToBase64. Итак, давайте взглянем на эту функцию и посмотрим, точно что она делает. Я упоминал выше, что нам нужно будет преобразовать наш файл в строку, чтобы отправить его в формате JSON. Теперь мы начнем делать это, вызывая эту функцию с метким названием.

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

  1. Он преобразует файл в Base64 (очень, очень длинная строка).
  2. Он передает эти данные функции, которая обрабатывает передачу ВСЕХ наших данных в наш API.
  3. Он отправляет ВСЕ наши данные в API.

Когда я говорю ВСЕ выше, это включает не только наш файл, но и другую информацию, которую мы собрали в нашей форме (название, описание, класс и предмет).

Теперь давайте разберем их еще немного. Я уверен, что вам интересна мощная «магия», которая происходит в этой единственной строке кода.

#1.

Мы вызываем функцию getBase64 и передаем ей this.state.file, файл, который мы сохранили в нашем локальном состоянии. Давайте посмотрим на эту функцию.

Итак, вы видите, что он принимает отправленный нами файл (this.state.file). Функция вернет обещание, которое без ошибок вернет файл, преобразованный в новый формат, по сути, Base64. Если вы console.log вернетесь, вы увидите длинную, длинную, длинную строку, которая выглядит как чепуха. Это формат закодированной строки, которую мы теперь можем отправлять в формате JSON.

Требуется небольшая очистка, чтобы убедиться, что у вас есть только Base64 самого файла. Все это выглядело великолепно, но всякий раз, когда я пытался получить его, я получал сообщение об ошибке. Проблема заключалась в том, что когда JavaScript конвертирует файл в формат Base64, он добавляет к нему префикс, например, «data:application/pdf;base64» (затем фактический код Base64). Поэтому, когда вы вскоре увидите шаг, когда мы конвертируем Base64 обратно в читаемый файл, это невозможно, потому что «data:application/pdf;base64» (файл Base64) не был частью исходного файла Base64.

Если вы видите выше в reader.onload, вы видите, что мы используем split, чтобы разбить возвращаемую дату на две части: префикс, добавленный Javascript, и преобразованные в Base64 данные файл. Это представлено разрешением(reader.result.split(‘,’)[1])

Поскольку первым элементом в [0] будет «data:application/pdf;base64», а мы разделяем данные запятой, второй элемент или [1] — это преобразованные в Base64 данные файла.

Теперь это подводит нас к следующему шагу.

#2.

.then принимает возвращаемое функцией значение, которое является промисом (так же, как использование .then после fetch) и передает это обещание анонимной функции с аргументом data, передаваемым функции, handleSubmitWithFile(data).

#3.

Функция handleSubmitWithFile принимает свой аргумент (данные), использует его как данные, отправляемые в виде файла, а также берет остальные данные из локального состояния и отправляет ВСЕ. к API.

Здесь параметр fileData — это файл, преобразованный в формате Base64.

Когда все данные отправляются в API, вы можете видеть, что название, описание и имя_файла берутся из локального состояния, из оригинальная ручка Изменить. А file происходит из fileData (данные файла, преобразованные в Base64), которые были переданы в функцию.

После этой отправки данные отправляются в API.

Та-даа!

Отлично, но как теперь вернуть его? Я учитель, который просмотрел урок, который вы опубликовали, и думаю, что он звучит точно так же, как то, что я мог бы использовать. Как мне его скачать.

Теперь давайте взглянем на внутренний API.

Самое главное — это контроллер для уроков, который содержит все данные, которые мы разместили выше. Давайте взглянем. Кроме того, напомню, что это API Ruby on Rails, который я использую для своей серверной части.

Вы должны увидеть некоторые из знакомых параметров в lesson_params. Но самое главное, мы хотим сосредоточиться на том, что нам нужно require в верхней части контроллера и на странице show.

Таким образом, приложение извлекает и отображает все уроки, которые были добавлены в приложение.

Когда я нажимаю «Нажмите, чтобы увидеть подробности», я не хочу видеть эту длинную строку Base64, я просто хочу увидеть файл. Давайте посмотрим, как это выглядит, когда я нажимаю на него.

Ах, вот оно!

План урока – 155 – составные слова.docx

Это не Base64, это название файла. Как мы это сделали? Давайте вернемся к API, а затем посмотрим, как получить все это во внешнем интерфейсе.

Итак, снова взглянув на lessons_controller.rb и зная, что нам нужно что-то требовать и сделать что-то конкретное со страницей show, давайте возьмем это. один шаг за раз.

Во-первых, чтобы что-то делать с Base64, нам нужно потребовать. Для этого в верхней части страницы нам просто нужно добавить следующее.

Отлично, теперь мы можем преобразовать наш файл, который теперь находится в формате Base64, обратно в исходный формат, когда это необходимо. Это делается на странице show. Давайте взглянем на код страницы урока show.

Итак, первая строка довольно проста, она находит конкретный урок на основе его идентификатора. Это вторая строка, которая выполняет «магию».

send_data — это то, что будет возвращать наш файл обратно при доступе к странице показа определенного урока. Таким образом, вместо того, чтобы приложение загружало новую страницу просмотра, содержащую информацию в параметрах, оно отправляет сами данные файла. Но опять же, мне не нужна эта беспорядочная длинная строка, мне нужен тот же файл, который я могу открыть и прочитать, который есть на моем компьютере. Тот, который я загрузил, чтобы другой учитель тоже мог его скачать и использовать. Вот что делает Base64.decode64(@lesson.file). Он берет длинную строку и преобразует ее обратно в пригодный для использования и читаемый файл.

И последнее, что мне нужно, это имя файла.

Спасибо, имя файла: @lesson.file_name.

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

Итак, давайте завершим это и перенесем на страницу. Вот напоминание о том, чего мы хотим.

Не беспокойтесь о разделе комментариев. Давайте просто сосредоточимся на верхней половине. Теперь я предполагаю, что вы знаете, как отображать плитку, описание и тому подобное с помощью реквизита (если вы знакомы с React). Но обратите внимание на название файла 155 Lesson Plan — Compound Words.docx.

Это другой цвет шрифта. И это не потому, что я решил изменить CSS этой строки. Потому что это ссылка. Помните из приведенного выше API send_data, который мы использовали на странице show? Когда вы нажимаете на эту ссылку, она отправляет файл на ваш компьютер.

Хотите увидеть код? Конечно, вы делаете.

Это просто тег ‹a›. href — это ссылка на страницу показа этого урока с идентификатором конкретного урока, вставленным в конкретный адрес (${this.props.lesson.id}). А внутренний текст — это имя файла, который мы сохранили ({this.props.lesson.file_name}).

И вуаля!

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

Я также собираюсь добавить ссылку на демонстрацию этого приложения, чтобы вы могли увидеть все это в действии, что также может внести дополнительную ясность.