Загрузка фотографий H5 и сводка заполнения ямы

внешний интерфейс JavaScript Vue.js WeUI

предисловие

Недавняя работа была выполнена с использованием проекта Vue + Vux Mobile Terminal, есть спрос на картинки для загрузки фотографий, найти VUX не было достигнуто, через неофициальный опросvux-uploaderПосле не очень хорошо себя чувствую.

На самом деле многие готовые решения, которые были реализованы, уже можно найти в Интернете, но при изучении этого требования я обнаружил, что в различных решениях реализации также есть некоторые точки знаний, поэтому я сделал колесо самостоятельно.vux-uploader-component, и запишите один или два.

нужно

Требования к интерактивным функциям компонентов следующие:

  1. html5 звонок на камеру телефона
  2. Изображение рендеринга миниатюру
  3. Фронтальные сжатые изображения
  4. Предварительный просмотр большого изображения
  5. удалить текущую картинку
  6. автоматическая загрузка

Схема реализации некоторых ключевых технических моментов

использоватьhtml media captureВызов камеры на мобильный телефон

<input type="file" accept="image/*"  capture />

Поскольку это входит в спецификацию HTML5, наиболее важным вопросом должна быть совместимость.

html-media-capture-caniuse

html-media-capture

Видно, что совместимость приемлема для большинства основных платформ.andriod2-4 поддерживаются, только вiosПоддержка 6-10 не так хороша.

Если вам интересно, вы можете проверить совместимость на своем мобильном телефоне.

html-media-capture-demo

html-media-capture demo

использоватьULR.createObjectURLПолучить адрес изображения

blobURL = ULR.createObjectURL(object)

Параметр объекта может бытьFile,Blob,MediaSource

Отсюда может возникнуть несколько вопросов:

  • Известные способы получения адреса изображения:URL.createObjectURLа такжеFileReader.readAsDataURL, что следует использовать? Почему?
  • существуетIOSКартинка, полученная при фотосъемке в камере, будет автоматически поворачиваться, почему? Как с этим бороться?
  • Fileа такжеBlobКаковы отношения?Blob URLа такжеData URLКакая разница?Data URLкак конвертироватьBlob?

использоватьcanvasсжимать изображения

Компрессию можно сделать двумя способами:

  • Установите максимальное ограничение ширины, чтобы пропорционально уменьшить ширину и высоту изображения.

    canvas.width = Math.min(image.naturalWidth, option.maxWidth)
    const ratio = canvas.width / image.naturalWidth
    canvas.height = image.naturalHeight * ratio
    
  • canvas.toDataURLУкажите поколениеjpegилиwebpФормат изображения, вы можете указать от 0 до 1encoderOptions

    dataURL = canvas.toDataURL("image/jpeg", encoderOptions)
    

Окончательный размер сгенерированного изображения = исходный размер изображения *ratio * encoderOption.

использоватьFormDataзагружать

const formData = new FormData()
formData.append('file', blob)

ЭтоXHRПродукт уровня 2, которые можно легко вставить в виде пар ключ-значение.

Самым большим преимуществом является то, что это может бытьXMLHttpRequest.send()отправлять двоичные файлы асинхронно.

Позже вы также можете пройтиBlobизsliceдля расширения функции многокомпонентной загрузки.

Анализ очков знаний

Разница между FileReader и URL.createObjectURL

оFileReaderа такжеURL.createObjectURLИспользование не будет подробно описываться, если вам интересно, вы можете сами погуглить.

Нам просто нужно знать сейчас

  • пройти черезFileReader.readAsDataURL(file)может получитьdata:base64Нить

  • пройти черезURL.createObjectURL(blob)Может получить память текущего файлаURL

Поскольку эти два API могут удовлетворить потребности нашего приобретения, ониразницакуда?

1. Время выполнения

  • createObjectURLвыполняется синхронно (немедленно)
  • FileReader.readAsDataURLвыполняется асинхронно (через некоторое время)

2. Использование памяти

  • createObjectURLвернуть группуhashизurl, и сохраняется в памяти до тех пор, покаdocumentзапущенныйunloadсобытия (например:document close) или выполнитьrevokeObjectURLосвободить.
  • FileReader.readAsDataURLзатем возвращает строку, содержащую много символовbase64и будет сравниться сblob urlПотребляет больше памяти, но будет автоматически очищаться из памяти, когда не используется (через механизм сборки мусора).

3. Совместимость

  • createObjectURLПоддерживает все современные браузеры, начиная с IE10.
  • FileReader.readAsDataURLТакже поддерживает все современные браузеры, начиная с IE10.

Из приведенных выше ответов нетрудно увидеть, что преимущества и недостатки двух

  • использоватьcreateObjectURLСохранить производительность и быстрее, но необходимость вручную выпустить без использования памяти
  • Если вас не волнуют проблемы с производительностью устройства и вы хотите получать изображенияbase64, рекомендуется использоватьFileReader.readAsDataURL

Ссылаться на

Изображение, сделанное камерой, будет вращаться

сверхуcreateObjectURLПолучив адрес изображения, мы можем вставить его в элемент страницы.background-imageСобственность показывает это изображение, и симулятор на стороне ПК не показывает проблем, но изображение, сделанное реальным мобильным телефоном, будет иметь поворот на 90 ° против часовой стрелки.

Почему изображение с камеры перевернуто?

Это связано с тем, что EXIF ​​(формат файла сменного изображения) изображения, полученного с камеры, установит значение по умолчанию.orientation tag

В настоящее время толькоjpegИзображения формата будут иметь

orientation

:point_up_2: Картинка вышеorientation tagСоответствующая связь с углом поворота изображения

Как решить эту проблему?

1. Получите картинуorientation

  • Если необходимо учитывать совместимость, рекомендуется использоватьExif.js
  • Если вы не хотите иметь внешние зависимости, а требования совместимости не так высоки, вы можете использоватьDataViewполучить см.ответ высокой оценки stackoverflow

2. Согласно картинкеorientationсделать соответствующий поворот

switch (orientation) {
   case 2:
     // horizontal flip
     ctx.translate(width, 0);
     ctx.scale(-1, 1);
     break;
   case 3:
     // 180 rotate left
     ctx.translate(width, height);
     ctx.rotate(Math.PI);
     break;
   case 4:
     // vertical flip
     ctx.translate(0, height);
     ctx.scale(1, -1);
     break;
   case 5:
     // vertical flip + 90 rotate right
     ctx.rotate(0.5 * Math.PI);
     ctx.scale(1, -1);
     break;
   case 6:
     // 90 rotate right
     ctx.rotate(0.5 * Math.PI);
     ctx.translate(0, -height);
     break;
   case 7:
     // horizontal flip + 90 rotate right
     ctx.rotate(0.5 * Math.PI);
     ctx.translate(width, -height);
     ctx.scale(-1, 1);
     break;
   case 8:
     // 90 rotate left
     ctx.rotate(-0.5 * Math.PI);
     ctx.translate(-width, 0);
     break;

Ссылаться на

Отношения между файлом и большим двоичным объектом? Разница между URL-адресом BLOB-объекта и URL-адресом данных? Как преобразовать DataURL в Blob?

Связь между файлом и большим двоичным объектом

отinput onchangeВозвращаемый объект изображения на самом деле являетсяFileобъект.

а такжеBlobОбъект — это контейнер, используемый для упаковки двоичных файлов,Fileунаследовано отBlob.

FileReaderэто API, используемый для чтения файлов в памяти, поддерживающийFileа такжеBlobДва формата.

Разница между URL-адресом BLOB-объекта и URL-адресом данных

Blob Urlдоступно только в браузереURL.createObjectURL(blob)Создать, когда он не используется, требуетURL.revokeObjectURL(blobURL)освободить.

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

blobURL = URL.createObjectURL(blob)

// blob:http://localhost:8000/xxxxxxxx

Data URLsВы можете получить файлbase64.

data:[<mediatype>][;base64],<data>

mediatypeявляется строкой типа MIME, например, "image/jpeg" означает файл изображения в формате JPEG. Если этот параметр опущен, по умолчаниюtext/plain;charset=US-ASCII

в состоянии пройтиFileReader.readAsDataURLПолучать

const reader = new FileReader();
reader.addEventListener("load", e => {
    const dataURL = e.target.result;
})
reader.readAsDataURL(blob);

Как преобразовать DataURL в Blob?

function dataURItoBlob(dataURI) {
  // convert base64 to raw binary data held in a string
  // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
  var byteString = atob(dataURI.split(',')[1]);

  // separate out the mime component
  var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]

  // write the bytes of the string to an ArrayBuffer
  var ab = new ArrayBuffer(byteString.length);

  // create a view into the buffer
  var ia = new Uint8Array(ab);

  // set the bytes of the buffer to the correct values
  for (var i = 0; i < byteString.length; i++) {
      ia[i] = byteString.charCodeAt(i);
  }

  // write the ArrayBuffer to a blob, and you're done
  var blob = new Blob([ab], {type: mimeString});
  return blob;

}

Ссылаться на

Индикатор выполнения загрузки составляет 100% от начала загрузки, почему?

Как мы все знаем, в настоящее время мониторинг загружаемых файловрасписаниеОсновной способ - использовать XHRonprogressсобытие для достижения, но почему, когда я отлаживаю загрузку локально,onprogressЗвонили только один раз?

В XHR2 есть объект событияProgressEvent, этот объект можно получить из следующих событий прослушивания:

название события Время запуска
loadstart инициация запроса
progress передавать данные
abort Запрос был прерван (например,abort()Способ запуска)
error Запрос не выполнен
load После успешного выполнения запроса
timeout Запускается, когда время запроса истекает в течение указанного времени
loadend После завершения запроса (независимо от того, был ли запрос успешным или нет)

ProgressEventЦикл событий выглядит следующим образом:

  1. Запускается первым после инициирования каждого запросаloadstart, запрос выполненflagдляfalse

  2. комплектуется по запросуflagУстановить какtrueраньше, с50msинтервал до триггера опросаprogressмероприятие

  3. Когда запрос завершается, запрос завершаетсяflagдляtrue, в зависимости от статуса результата выполнения запроса, триггерabort,error,load,timeoutодин из них.

  4. Запускается, когда запрос завершенloadend

На данный момент мы очень четко знаем, почему, даже если мы загружаем локально, иprogressОткат вconsole.logПричина, по которой она выполняется только один раз:Событие локального запроса на загрузку длится менее 50 мс.

Просто настройте сеть на медленный 3G и загрузите большую картинку с пикселями высокой четкости, вы можете видетьprogressМероприятие начнется с50msинтервальные вызовы.

Ссылаться на

наконец

Небольшая волна продвижения основана наweuiКомпонент загрузки изображений Mobile Vue реализован в стилеvux-uploader-component

vux-uploader-component

Добро пожаловать на сканирование кода, опыт, звезда, проблема, пиар :)