⚠️Эта статья является первой подписанной статьей сообщества Nuggets, перепечатка без разрешения запрещена.
В повседневной работе загрузка файлов — очень распространенная функция. В процессе разработки проекта мы обычно используем некоторые зрелые компоненты загрузки для достижения соответствующих функций. Вообще говоря, зрелый компонент загрузки не только обеспечивает красивый пользовательский интерфейс или хороший интерактивный опыт, но также предоставляет множество различных методов загрузки для удовлетворения потребностей различных сценариев.
Вообще, в нашей работе есть в основном 8 сценариев загрузки файлов, каждый из которых использует разные технологии, и есть много деталей, которые требуют нашего дополнительного внимания. Сегодня Brother A Bao представит вам обзор этих 8 сценариев, чтобы вы могли лучше понять функции, предоставляемые зрелым компонентом загрузки. Прочитав эту статью, вы будете знать следующее:
-
Загрузка одного файла: использовать
input
элементальaccept
Атрибуты ограничивают тип загружаемых файлов, используйте JS для определения типа файлов и использованияKoaРеализовать функцию загрузки одного файла; -
Загрузка нескольких файлов: используйте
input
элементальmultiple
Атрибуты поддерживают выбор нескольких файлов и использованиеKoaРеализовать функцию загрузки нескольких файлов; -
Загрузка каталога: использовать
input
на элементеwebkitdirectory
Атрибуты поддерживают функцию и использование загрузки каталогаKoaРеализовать функцию загрузки и хранения каталогов в соответствии с файловой структурой каталогов; -
Сжатая загрузка каталога: на основе загрузки каталога используйтеJSZipРеализовать функцию загрузки сжатого каталога;
-
Загрузка с помощью перетаскивания: используйте события перетаскивания иDataTransferВ объекте реализована функция перетаскивания и загрузки;
-
Загрузка буфера обмена: Воспользуйтесь преимуществами событий буфера обмена иClipboardAPI реализует функцию загрузки буфера обмена;
-
Загрузка больших файлов кусками: используйтеBlob.slice,SparkMD5и сторонние библиотекиasync-poolРеализовать функцию одновременной загрузки больших файлов;
-
Загрузка сервера: используйте сторонние библиотекиform-dataРеализует функцию потоковой загрузки файлов на сервер.
1. Загрузка одного файла
Для сцены загрузки одного файла наиболее распространенной является сцена загрузки изображения, поэтому давайте возьмем загрузку изображения в качестве примера, чтобы представить основной процесс загрузки одного файла.
1.1 Интерфейсный код
html
В следующем коде мы передаемinput
элементальaccept
Атрибут ограничивает тип загружаемого файла. использовать здесьimage/*
Ограничьте выбор только файлами изображений, конечно, вы также можете установить определенные типы, такие какimage/png
илиimage/png,image/jpeg
.
<input id="uploadFile" type="file" accept="image/*" />
<button id="submit" onclick="uploadFile()">上传文件</button>
Обратите внимание, что хотя мы помещаем элемент вводаaccept
свойство установлено на image/png
. Но если пользователь ставитjpg/jpeg
Имя суффикса изображения формата изменено на.png
, вы можете успешно обойти это ограничение. Чтобы исправить это, мы можем определить правильный тип файла, прочитав двоичные данные в файле.
Для просмотра бинарных данных, соответствующих картинке, мы можем использовать некоторые готовые редакторы, например, под платформу Windows.WinHexили под платформу macOSSynalyze It! ProШестнадцатеричный редактор. Здесь мы используемSynalyze It! ProЭтот редактор для просмотра двоичных данных, соответствующих аватару Брата Абао.
Так может ли интерфейс прочитать двоичные данные файла без помощи инструментов? Ответ положительный, и брат А. Бао не будет его здесь представлять. Если вам интересно, вы можете прочитатьКак JavaScript определяет тип файла?Эта статья. Кроме того, следует отметить, чтоinput
элементaccept
Есть проблемы совместимости со свойствами. Например, IE 9 и более ранние версии не поддерживаются, как показано на следующем рисунке:
(Источник изображения --стереть newser.com/input-file-…
js
const uploadFileEle = document.querySelector("#uploadFile");
const request = axios.create({
baseURL: "http://localhost:3000/upload",
timeout: 60000,
});
async function uploadFile() {
if (!uploadFileEle.files.length) return;
const file = uploadFileEle.files[0]; // 获取单个文件
// 省略文件的校验过程,比如文件类型、大小校验
upload({
url: "/single",
file,
});
}
function upload({ url, file, fieldName = "file" }) {
let formData = new FormData();
formData.set(fieldName, file);
request.post(url, formData, {
// 监听上传进度
onUploadProgress: function (progressEvent) {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(percentCompleted);
},
});
}
В приведенном выше коде мы сначала читаемFileОбъекты инкапсулируются какFormDataобъект, а затем использоватьAxiosпримерpost
Метод реализует функцию загрузки файла. Перед загрузкой, установив объект конфигурации запросаonUploadProgress
свойство, вы можете получить ход загрузки файла.
1.2 Код сервера
KoaЭто простой и удобный веб-фреймворк, отличающийся элегантностью, простотой, малым весом и высокой степенью свободы. Поэтому мы выбираем его для создания файлового сервиса и используем следующее промежуточное ПО для реализации соответствующих функций:
- koa-static: промежуточное ПО для обработки статических ресурсов;
- @koa/cors: промежуточное ПО для обработки междоменных запросов;
-
@koa/multer:иметь дело с
multipart/form-data
Промежуточное программное обеспечение; - @koa/router: Промежуточное программное обеспечение, которое обрабатывает маршрутизацию.
const path = require("path");
const Koa = require("koa");
const serve = require("koa-static");
const cors = require("@koa/cors");
const multer = require("@koa/multer");
const Router = require("@koa/router");
const app = new Koa();
const router = new Router();
const PORT = 3000;
// 上传后资源的URL地址
const RESOURCE_URL = `http://localhost:${PORT}`;
// 存储上传文件的目录
const UPLOAD_DIR = path.join(__dirname, "/public/upload");
const storage = multer.diskStorage({
destination: async function (req, file, cb) {
// 设置文件的存储目录
cb(null, UPLOAD_DIR);
},
filename: function (req, file, cb) {
// 设置文件名
cb(null, `${file.originalname}`);
},
});
const multerUpload = multer({ storage });
router.get("/", async (ctx) => {
ctx.body = "欢迎使用文件服务(by 阿宝哥)";
});
router.post(
"/upload/single",
async (ctx, next) => {
try {
await next();
ctx.body = {
code: 1,
msg: "文件上传成功",
url: `${RESOURCE_URL}/${ctx.file.originalname}`,
};
} catch (error) {
ctx.body = {
code: 0,
msg: "文件上传失败"
};
}
},
multerUpload.single("file")
);
// 注册中间件
app.use(cors());
app.use(serve(UPLOAD_DIR));
app.use(router.routes()).use(router.allowedMethods());
app.listen(PORT, () => {
console.log(`app starting at port ${PORT}`);
});
Приведенный выше код относительно прост, поэтому мы не будем его представлять.KoaЯдро очень простое, а расширенные функции реализованы через промежуточное ПО. Например, маршруты, использованные в примере,CORS, статическая обработка ресурсов и другие функции реализуются через промежуточное ПО. Итак, чтобы освоитьKoaЯдром этой структуры является освоение механизма промежуточного программного обеспечения. Если вы хотите узнать больше, вы можете прочитатьКак лучше понять промежуточное ПО и луковую модельЭта статья. Фактически, помимо загрузки одного файла, в сценарии загрузки файлов мы также можем загружать несколько файлов одновременно.
Пример загрузки одного файла:single-file-upload
2. Загрузка нескольких файлов
Чтобы загрузить несколько файлов, сначала нам нужно разрешить пользователю выбирать несколько файлов одновременно. Для этого мы можем использоватьinput
элементальmultiple
Атрибуты. как описано ранееaccept
Как и свойства, это свойство также имеет проблемы с совместимостью, как показано на следующем рисунке.
(Источник изображения --потрите newser.com/madonna-api_htm…
2.1 Интерфейсный код
html
По сравнению с кодом для загрузки одного файла в сценарии загрузки нескольких файловinput
еще один элементmultiple
Атрибуты:
<input id="uploadFile" type="file" accept="image/*" multiple />
<button id="submit" onclick="uploadFile()">上传文件</button>
js
В коде для загрузки одного файла мы передаемuploadFileEle.files[0]
Получить один файл, а для нескольких загрузок файлов нам нужно получить список выбранных файлов, т.е. черезuploadFileEle.files
чтобы получить, он возвращаетFileListобъект.
async function uploadFile() {
if (!uploadFileEle.files.length) return;
const files = Array.from(uploadFileEle.files);
upload({
url: "/multiple",
files,
});
}
Поскольку мы хотим поддерживать загрузку нескольких файлов, нам нужно обновлять их синхронно.upload
функция. Соответствующая логика обработки состоит в том, чтобы просмотреть список файлов, а затем использоватьFormDataобъектappend
метод добавления нескольких файлов, конкретный код выглядит следующим образом:
function upload({ url, files, fieldName = "file" }) {
let formData = new FormData();
files.forEach((file) => {
formData.append(fieldName, file);
});
request.post(url, formData, {
// 监听上传进度
onUploadProgress: function (progressEvent) {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(percentCompleted);
},
});
}
2.2 Код сервера
В следующем коде мы определяем новый маршрут —/upload/multiple
для обработки нескольких загрузок файлов. Когда все файлы будут успешно загружены, он вернет список URL-адресов загруженных файлов:
router.post(
"/upload/multiple",
async (ctx, next) => {
try {
await next();
urls = ctx.files.file.map(file => `${RESOURCE_URL}/${file.originalname}`);
ctx.body = {
code: 1,
msg: "文件上传成功",
urls
};
} catch (error) {
ctx.body = {
code: 0,
msg: "文件上传失败",
};
}
},
multerUpload.fields([
{
name: "file", // 与FormData表单项的fieldName想对应
},
])
);
После введения функции загрузки одного файла и нескольких файлов, давайте представим функцию загрузки каталога.
Пример загрузки нескольких файлов:multiple-file-upload
3. Загрузка каталога
Может быть, ты еще не знаешь,input
На элементе есть еще одинwebkitdirectory
Атрибуты. когда установленоwebkitdirectory
После свойств мы можем выбрать каталог.
<input id="uploadFile" type="file" accept="image/*" webkitdirectory />
Когда мы выбираем указанный каталог, например, на рабочем столе Abaogeimages
каталоге отображается следующее окно подтверждения:
После нажатия кнопки загрузки мы можем получить список файлов. Файловые объекты в списке содержатwebkitRelativePath
Атрибут, используемый для представления относительного пути к текущему файлу.
Хотя черезwebkitdirectory
Свойства могут легко реализовать функцию выбора каталога, но в реальных проектах нам также необходимо учитывать его совместимость. Например, версии ниже IE 11 не поддерживают это свойство, а совместимость с другими браузерами показана на следующем рисунке:
(Источник изображения --потрите newser.com/?search=Web…
пониматьwebkitdirectory
Совместимость атрибутов, давайте сначала представим код реализации внешнего интерфейса.
3.1 Интерфейсный код
Чтобы позволить серверу хранить соответствующие файлы в соответствии с фактической структурой каталогов, нам нужно указать путь к текущему файлу на сервер при добавлении элемента формы. Кроме того, для обеспечения@koa/multer
Чтобы иметь возможность правильно обрабатывать путь к файлу, нам нужно выполнить специальную обработку пути. то есть поставить/
замените косую черту на@
символ. Соответствующий метод обработки выглядит следующим образом:
function upload({ url, files, fieldName = "file" }) {
let formData = new FormData();
files.forEach((file, i) => {
formData.append(
fieldName,
files[i],
files[i].webkitRelativePath.replace(/\//g, "@");
);
});
request.post(url, formData); // 省略上传进度处理
}
3.2 Код сервера
Основное различие между загрузкой каталога и многофайловой загрузкой кода на стороне сервера заключается в том, что@koa/multer
Объекты конфигурации промежуточного программного обеспечения отличаются. существуетdestination
В функции, соответствующей атрибуту, нам нужно поместить имя файла в поле@
вернуться к/
, а затем создайте каталог на основе фактического пути к файлу.
const fse = require("fs-extra");
const storage = multer.diskStorage({
destination: async function (req, file, cb) {
// images@image-1.jpeg => images/image-1.jpeg
let relativePath = file.originalname.replace(/@/g, path.sep);
let index = relativePath.lastIndexOf(path.sep);
let fileDir = path.join(UPLOAD_DIR, relativePath.substr(0, index));
// 确保文件目录存在,若不存在的话,会自动创建
await fse.ensureDir(fileDir);
cb(null, fileDir);
},
filename: function (req, file, cb) {
let parts = file.originalname.split("@");
cb(null, `${parts[parts.length - 1]}`);
},
});
Теперь, когда мы реализовали функцию загрузки каталога, можно ли файлы в каталоге сжать в сжатый пакет, а затем загрузить? Ответ положительный, тогда давайте представим, как реализовать функцию загрузки сжатого каталога.
Пример загрузки каталога:directory-upload
В-четвертых, загрузка сжатого каталога
существуетКак JavaScript распаковывает ZIP-файлы онлайн?В этой статье я расскажу, как использовать его на стороне браузера.JSZipВ этой библиотеке реализована функция распаковки ZIP файлов онлайн.JSZipПомимо разбора ZIP-файлов, эту библиотеку также можно использовать дляСоздать и редактироватьZIP-файл. использоватьJSZipпредоставляется этой библиотекойAPI, мы можем сжать все файлы в каталоге в ZIP-файл, а затем загрузить сгенерированный ZIP-файл на сервер.
4.1 Интерфейсный код
на экземпляре JSZipfile(name, data [,options])
способ добавления файлов в ZIP-файл. На основе этого метода мы можем инкапсулироватьgenerateZipFile
Функция для сжатия списка файлов в каталоге в ZIP-файл. Ниже приведеныgenerateZipFile
Конкретная реализация функции:
function generateZipFile(
zipName, files,
options = { type: "blob", compression: "DEFLATE" }
) {
return new Promise((resolve, reject) => {
const zip = new JSZip();
for (let i = 0; i < files.length; i++) {
zip.file(files[i].webkitRelativePath, files[i]);
}
zip.generateAsync(options).then(function (blob) {
zipName = zipName || Date.now() + ".zip";
const zipFile = new File([blob], zipName, {
type: "application/zip",
});
resolve(zipFile);
});
});
}
После созданияgenerateZipFile
После функции нам нужно обновить введенную ранееuploadFile
функция:
async function uploadFile() {
let fileList = uploadFileEle.files;
if (!fileList.length) return;
let webkitRelativePath = fileList[0].webkitRelativePath;
let zipFileName = webkitRelativePath.split("/")[0] + ".zip";
let zipFile = await generateZipFile(zipFileName, fileList);
upload({
url: "/single",
file: zipFile,
fileName: zipFileName
});
}
вышеuploadFile
функция, мы вернемсяFileListобъект для обработки, то есть вызовgenerateZipFile
Функция для генерации ZIP-файла. Кроме того, для того, чтобы получить сжатый файл на сервере, вы можете получить имя файла, мыupload
функция добавляетfileName
параметр, который используется для вызоваformData.append
метод, установите имя загружаемого файла:
function upload({ url, file, fileName, fieldName = "file" }) {
if (!url || !file) return;
let formData = new FormData();
formData.append(
fieldName, file, fileName
);
request.post(url, formData); // 省略上传进度跟踪
}
Выше приведена загрузка сжатого каталога, код JS интерфейсной части, а код на стороне сервера может ссылаться на соответствующий код загрузки одного файла выше.
Пример загрузки сжатого каталога:directory-compress-upload
Пять, перетащите загрузку
Чтобы реализовать функцию загрузки с помощью перетаскивания, нам нужно сначала понять события, связанные с перетаскиванием. Напримерdrag
,dragend
,dragenter
,dragover
илиdrop
события и т. д. Здесь мы вводим только события перетаскивания, которые будут использоваться далее:
-
dragenter
: срабатывает, когда элемент или выделенный текст перетаскиваются в освобождаемую цель; -
dragover
: срабатывает, когда элемент или выделенный текст перетаскиваются на освобождаемую цель (каждые 100 мс); -
dragleave
: срабатывает, когда перетаскиваемый элемент или выделенный текст покидают освобождаемую цель; -
drop
: Запускается, когда элемент или выделенный текст высвобождаются на освобождаемой цели.
Основываясь на приведенных выше событиях, мы можем улучшить пользовательский опыт перетаскивания. Например, когда элемент, перетаскиваемый пользователем, попадает в целевую область, целевая область выделяется. Удаляет выделение, когда перетаскиваемый пользователем элемент покидает целевую область. очевидно, когдаdrop
После срабатывания события перетаскиваемый элемент был помещен в целевую область, а затем нам нужно получить соответствующие данные.
Так как же получить данные, соответствующие перетаскиванию? Затем нам нужно использоватьDataTransferОбъект, который содержит данные во время процесса перетаскивания. Он может содержать один или несколько элементов данных, которые могут относиться к одному или нескольким типам данных. Если операция перетаскивания включает в себя перетаскивание файлов, мы можем передатьDataTransferобъектfiles
свойство, чтобы получить список файлов.
После введения знаний, связанных с загрузкой с помощью перетаскивания, давайте посмотрим, как реализовать функцию загрузки с помощью перетаскивания.
5.1 Интерфейсный код
html
<div id="dropArea">
<p>拖拽上传文件</p>
<div id="imagePreview"></div>
</div>
css
#dropArea {
width: 300px;
height: 300px;
border: 1px dashed gray;
margin-bottom: 20px;
}
#dropArea p {
text-align: center;
color: #999;
}
#dropArea.highlighted {
background-color: #ddd;
}
#imagePreview {
max-height: 250px;
overflow-y: scroll;
}
#imagePreview img {
width: 100%;
display: block;
margin: auto;
}
js
Чтобы каждый мог лучше прочитать соответствующий код загрузки с помощью перетаскивания, мы разделим код на 4 части, чтобы объяснить:
1. Запретить поведение перетаскивания по умолчанию
const dropAreaEle = document.querySelector("#dropArea");
const imgPreviewEle = document.querySelector("#imagePreview");
const IMAGE_MIME_REGEX = /^image\/(jpe?g|gif|png)$/i;
["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => {
dropAreaEle.addEventListener(eventName, preventDefaults, false);
document.body.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
2, переключите выделение целевой области
["dragenter", "dragover"].forEach((eventName) => {
dropAreaEle.addEventListener(eventName, highlight, false);
});
["dragleave", "drop"].forEach((eventName) => {
dropAreaEle.addEventListener(eventName, unhighlight, false);
});
// 添加高亮样式
function highlight(e) {
dropAreaEle.classList.add("highlighted");
}
// 移除高亮样式
function unhighlight(e) {
dropAreaEle.classList.remove("highlighted");
}
3, предварительный просмотр изображения процесса
dropAreaEle.addEventListener("drop", handleDrop, false);
function handleDrop(e) {
const dt = e.dataTransfer;
const files = [...dt.files];
files.forEach((file) => {
previewImage(file, imgPreviewEle);
});
// 省略文件上传代码
}
function previewImage(file, container) {
if (IMAGE_MIME_REGEX.test(file.type)) {
const reader = new FileReader();
reader.onload = function (e) {
let img = document.createElement("img");
img.src = e.target.result;
container.append(img);
};
reader.readAsDataURL(file);
}
}
4. Загрузка файла
function handleDrop(e) {
const dt = e.dataTransfer;
const files = [...dt.files];
// 省略图片预览代码
files.forEach((file) => {
upload({
url: "/single",
file,
});
});
}
const request = axios.create({
baseURL: "http://localhost:3000/upload",
timeout: 60000,
});
function upload({ url, file, fieldName = "file" }) {
let formData = new FormData();
formData.set(fieldName, file);
request.post(url, formData, {
// 监听上传进度
onUploadProgress: function (progressEvent) {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(percentCompleted);
},
});
}
Загрузка с помощью перетаскивания является относительно распространенным сценарием, и многие зрелые компоненты загрузки поддерживают эту функцию. Фактически, помимо перетаскивания и загрузки, вы также можете использовать буфер обмена для реализации функции копирования и загрузки.
Перетащите пример загрузки:drag-drop-upload
6. Загрузка буфера обмена
Прежде чем представить, как реализовать функцию загрузки буфера обмена, нам нужно понятьClipboardAPI.Clipboard
Интерфейс реализованClipboardAPI, если пользователь предоставляет соответствующие разрешения, предоставляет доступ для чтения и записи к системному буферу обмена. В веб-приложенииClipboardAPI можно использовать для реализации функций вырезания, копирования и вставки. Этот API используется для заменыdocument.execCommandAPI для реализации операций с буфером обмена.
В реальном проекте нам не нужно вручную создаватьClipboard
Объект, но поnavigator.clipboard
получитьClipboard
Объект:
в полученииClipboard
После объекта мы можем использовать API, предоставляемый объектом, для доступа к буферу обмена, например:
navigator.clipboard.readText().then(
clipText => document.querySelector(".editor").innerText = clipText
);
Приведенный выше код будет включать в себя HTML.editor
Содержимое первого элемента класса заменяется содержимым буфера обмена. Если буфер обмена пуст или не содержит текста, содержимое элемента будет очищено. Это связано с тем, что когда буфер обмена пуст или не содержит текста,readText
Метод возвращает пустую строку.
использоватьClipboardAPI Мы можем легко управлять буфером обмена, но его совместимость также должна учитываться в процессе фактического использования проекта:
(Источник изображения --Очистить Newser.com/A sync – Обработать PB…
Чтобы реализовать функцию загрузки буфера обмена, ее можно разделить на следующие 3 этапа:
- Слушайте событие вставки контейнера;
- читать и анализировать содержимое буфера обмена;
- динамическая сборка
FormData
объект и загрузить.
Разобравшись с приведенными выше шагами, давайте проанализируем конкретный код реализации.
6.1 Интерфейсный код
html
<div id="uploadArea">
<p>请先复制图片后再执行粘贴操作</p>
</div>
css
#uploadArea {
width: 400px;
height: 400px;
border: 1px dashed gray;
display: table-cell;
vertical-align: middle;
}
#uploadArea p {
text-align: center;
color: #999;
}
#uploadArea img {
max-width: 100%;
max-height: 100%;
display: block;
margin: auto;
}
js
В следующем коде мы используемaddEventListener
методuploadArea
контейнер добавитьpaste
событие. В соответствующей функции обработчика событий мы отдадим приоритет определению того, поддерживает ли текущий браузер асинхронныйClipboardAPI. Если поддерживается, он будет переданnavigator.clipboard.read
способ чтения содержимого буфера обмена. После прочтения содержимого мы оценим, содержит ли элемент буфера обмена ресурсы изображения по регулярности, и если да, то вызовемpreviewImage
Метод выполняет операцию предварительного просмотра изображения и возвращаетblob
Объект сохраняется для последующих операций загрузки.
const IMAGE_MIME_REGEX = /^image\/(jpe?g|gif|png)$/i;
const uploadAreaEle = document.querySelector("#uploadArea");
uploadAreaEle.addEventListener("paste", async (e) => {
e.preventDefault();
const files = [];
if (navigator.clipboard) {
let clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
for (const type of clipboardItem.types) {
if (IMAGE_MIME_REGEX.test(type)) {
const blob = await clipboardItem.getType(type);
insertImage(blob, uploadAreaEle);
files.push(blob);
}
}
}
} else {
const items = e.clipboardData.items;
for (let i = 0; i < items.length; i++) {
if (IMAGE_MIME_REGEX.test(items[i].type)) {
let file = items[i].getAsFile();
insertImage(file, uploadAreaEle);
files.push(file);
}
}
}
if (files.length > 0) {
confirm("剪贴板检测到图片文件,是否执行上传操作?")
&& upload({
url: "/multiple",
files,
});
}
});
Если текущий браузер не поддерживает асинхронностьClipboardAPI, пытаемся пройтиe.clipboardData.items
для доступа к содержимому буфера обмена. Следует отметить, что при обходе элементов содержимого буфера обмена мы передаемgetAsFile
способ получить содержимое буфера обмена. Конечно, этот метод также имеет проблемы с совместимостью, как показано на следующем рисунке:
(Источник изображения --потрите news.com/madonna-api_datang…
Как упоминалось ранее, при парсинге из буфера обмена в ресурс изображения пользователю будет разрешен предварительный просмотр, эта функция основана наFileReaderAPI для достижения, соответствующий код выглядит следующим образом:
function previewImage(file, container) {
const reader = new FileReader();
reader.onload = function (e) {
let img = document.createElement("img");
img.src = e.target.result;
container.append(img);
};
reader.readAsDataURL(file);
}
После завершения пользовательского предварительного просмотра, если загрузка будет подтверждена, мы выполним операцию загрузки файла. Поскольку файл считывается из буфера обмена, перед загрузкой мы автоматически сгенерируем для него имя файла в соответствии с типом файла, которое имеет форму временной метки и файлового суффикса:
function upload({ url, files, fieldName = "file" }) {
let formData = new FormData();
files.forEach((file) => {
let fileName = +new Date() + "." + IMAGE_MIME_REGEX.exec(file.type)[1];
formData.append(fieldName, file, fileName);
});
request.post(url, formData);
}
Мы уже представили множество различных сценариев для загрузки файлов, теперь давайте представим «особый» сценарий —Загрузка большого файла.
Пример загрузки буфера обмена:clipboard-upload
7. Загрузка больших файлов кусками
Я думаю, вы уже знаете решение для загрузки больших файлов.При загрузке больших файлов, чтобы повысить эффективность загрузки, мы обычно используемBlob.sliceМетод обрезает большой файл в соответствии с указанным размером, а затем загружает его кусками через несколько потоков.После того, как все куски успешно загружены, сервер уведомляется о необходимости их объединения. Конкретный план обработки показан на следующем рисунке:
Так какКак реализовать одновременную загрузку больших файлов в JavaScript?В этой статье Брат Абао уже подробно представил схему одновременной загрузки больших файлов, поэтому я не буду ее здесь представлять. Давайте просто рассмотрим весь процесс одновременной загрузки больших файлов:
Мы представили сценарии загрузки файлов на стороне клиента ранее, но есть также сценарии загрузки файлов на стороне сервера. Например, после динамического создания плаката на сервере загрузите его на другой сервер или в OSS (службу хранения объектов) облачного поставщика. Ниже мыNode.jsВозьмите пример, чтобы представить, как загружать файлы на сервер.
Пример загрузки больших файлов кусками:big-file-upload
Восемь, загрузка сервера
Загрузка сервера — это загрузка файлов с одного сервера на другой. С помощью Гитхабаform-dataС функциями, предоставляемыми этой библиотекой, мы можем легко реализовать функцию загрузки на сервер. Давайте кратко представим функции загрузки одного файла и нескольких файлов:
8.1 Загрузка одного файла
const fs = require("fs");
const path = require("path");
const FormData = require("form-data");
const form1 = new FormData();
form1.append("file", fs.createReadStream(path.join(__dirname, "images/image-1.jpeg")));
form1.submit("http://localhost:3000/upload/single", (error, response) => {
if(error) {
console.log("单图上传失败");
return;
}
console.log("单图上传成功");
});
8.2 Загрузка нескольких файлов
const form2 = new FormData();
form2.append("file", fs.createReadStream(path.join(__dirname, "images/image-2.jpeg")));
form2.append("file", fs.createReadStream(path.join(__dirname, "images/image-3.jpeg")));
form2.submit("http://localhost:3000/upload/multiple", (error, response) => {
if(error) {
console.log("多图上传失败");
return;
}
console.log("多图上传成功");
});
Наблюдая за приведенным выше кодом, мы видим, что после созданияFormData
После объекта нам просто нужно пройтиfs.createReadStream
API создает читаемый поток, затем вызываетFormData
объектappend
метод для добавления элементов формы и, наконец, вызовsubmit
метод для выполнения операции отправки.
На самом деле, кромеReadableStream
Кроме,FormData
объектappend
Метод также поддерживает следующие типы:
const FormData = require('form-data');
const http = require('http');
const form = new FormData();
http.request('http://nodejs.org/images/logo.png', function(response) {
form.append('my_field', 'my value');
form.append('my_buffer', new Buffer(10));
form.append('my_logo', response);
});
Содержимое загрузки файла сервера представлено здесь, оform-dataДля других применений этой библиотеки, если вы заинтересованы, вы можете прочитать соответствующую документацию по использованию. На самом деле, помимо восьми описанных выше сценариев, в своей повседневной работе вы также можете использовать некоторые инструменты синхронизации, такие какSyncthingИнструменты синхронизации файлов реализуют передачу файлов. Хорошо, все содержание этой статьи было представлено, и, наконец, давайте подведем итоги.
Пример загрузки сервера:server-upload
9. Резюме
В этой статье брат Абао подробно описывает восемь сценариев загрузки файлов.Я надеюсь, что после прочтения этой статьи у вас будет определенное понимание технологий, лежащих в основе восьми сценариев. Из-за ограниченного места брат Абао не стал расширять введение иmultipart/form-data
Контент, связанный с типом, заинтересованные друзья могут узнать о нем сами.
Кроме того, в реальных проектах вы можете рассмотреть возможность использования зрелых сторонних компонентов напрямую, таких как количество звезд на Github.11K+изfilepond. Этот компонент использует архитектуру подключаемых модулей и предоставляет множество функций в виде подключаемых модулей, таких какFile encode,File rename,File poster,Image previewиImage cropЖдать. Одним словом, очень хороший компонент, если у вас будет возможность в будущем, можете попробовать.