Spec-Zone.ru › Phoenix

Загрузка файлов

Source

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

Встроенные функции

  • Спецификация допустимых файлов — задайте допустимые типы файлов, максимальное число файлов, максимальный размер файла и т. д. Когда клиент выбирает файл или файлы, метаданные файлов автоматически проверяются по спецификации. См. Phoenix.LiveView.allow_upload/3.

  • Реактивные записи — загрузки хранятся в assign @uploads сокета. Записи автоматически реагируют на изменение прогресса, ошибки, отмену и т. д.

  • Перетаскивание — используйте атрибут phx-drop-target для включения этой возможности. См. Phoenix.Component.live_file_input/1.

Разрешение загрузки файлов

Разрешить загрузку файлов можно, как правило, в mount, с помощью allow_upload/3.

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

@impl Phoenix.LiveView
def mount(_params, _session, socket) do
  {:ok,
   socket
   |> assign(:uploaded_files, [])
   |> allow_upload(:avatar, accept: ~w(.jpg .jpeg), max_entries: 2)}
end

На этом пока всё! Позже мы вернёмся к LiveView, чтобы реализовать некоторые обратные вызовы, связанные с формой и загрузкой файлов, но большая часть функциональности загрузки реализуется в шаблоне.

Стоит ознакомиться с документацией по allow_upload/3 и изучить доступные параметры, среди которых есть, например, auto_upload для автоматической загрузки файлов.

Отображение реактивных элементов

Используйте компонент Phoenix.Component.live_file_input/1, чтобы отобразить поле выбора файлов для загрузки:

<%!-- lib/my_app_web/live/upload_live.html.heex --%>

<form id="upload-form" phx-change="validate" phx-submit="save">
  <.live_file_input upload={@uploads.avatar} />
  <button type="submit">Upload</button>
</form>

Важно: Для формы необходимо задать phx-submit и phx-change.

Обратите внимание: хотя live_file_input/1 позволяет задавать дополнительные атрибуты поля выбора файла, многие атрибуты, такие как id, accept и multiple, будут заданы автоматически на основе спецификации allow_upload/3.

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

Записи загрузки

Загрузки хранятся в assign @uploads сокета. Каждая разрешённая загрузка содержит список записей независимо от значения :max_entries в спецификации allow_upload/3. Эти структуры записей содержат всю информацию о загрузке, включая прогресс, сведения о файле на клиенте, ошибки и т. д.

Рассмотрим пример с пояснениями:

<%!-- lib/my_app_web/live/upload_live.html.heex --%>

<%!-- use phx-drop-target with the upload ref to enable file drag and drop --%>
<section phx-drop-target={@uploads.avatar.ref}>
  <%!-- render each avatar entry --%>
  <article :for={entry <- @uploads.avatar.entries} class="upload-entry">
    <figure>
      <.live_img_preview entry={entry} />
      <figcaption>{entry.client_name}</figcaption>
    </figure>

    <%!-- entry.progress will update automatically for in-flight entries --%>
    <progress value={entry.progress} max="100"> {entry.progress}% </progress>

    <%!-- a regular click event whose handler will invoke Phoenix.LiveView.cancel_upload/3 --%>
    <button type="button" phx-click="cancel-upload" phx-value-ref={entry.ref} aria-label="cancel">&times;</button>

    <%!-- Phoenix.Component.upload_errors/2 returns a list of error atoms --%>
    <p :for={err <- upload_errors(@uploads.avatar, entry)} class="alert alert-danger">{error_to_string(err)}</p>
  </article>

  <%!-- Phoenix.Component.upload_errors/1 returns a list of error atoms --%>
  <p :for={err <- upload_errors(@uploads.avatar)} class="alert alert-danger">
    {error_to_string(err)}
  </p>
</section>

Элемент section в примере служит phx-drop-target для загрузки :avatar. Пользователи могут взаимодействовать с полем выбора файла или перетаскивать файлы на этот элемент, чтобы добавить новые записи.

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

Стилизация области для перетаскивания

Phoenix LiveView отслеживает события перетаскивания в браузере и добавляет к элементу-цели перетаскивания класс phx-drop-target-active, когда пользователь перетаскивает на него элемент.

При использовании TailwindCSS можно создать пользовательский вариант, который будет работать вместе с этим классом и позволит применять стили именно во время перетаскивания элемента на цель.

<%!-- assets/app.css --%>

@custom-variant phx-drop-target-active (.phx-drop-target-active&, .phx-drop-target-active &);

Этот вариант можно использовать в шаблонах HeEx следующим образом:

<%!-- lib/my_app_web/live/upload_live.html.heex --%>

<section phx-drop-target={@uploads.avatar.ref} class="phx-drop-target-active:scale-105">
<!-- ... -->
</section>

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

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

Проверка записей

Проверка выполняется автоматически на основе условий, заданных в allow_upload/3. Однако, как упоминалось ранее, для выполнения проверки необходимо задать phx-change для формы. Поэтому нужно реализовать как минимум минимальный обратный вызов:

@impl Phoenix.LiveView
def handle_event("validate", _params, socket) do
  {:noreply, socket}
end

Записи файлов, не соответствующих спецификации allow_upload/3, будут содержать ошибки. Используйте Phoenix.Component.upload_errors/2 и собственную вспомогательную функцию, чтобы вывести понятное сообщение об ошибке:

defp error_to_string(:too_large), do: "Too large"
defp error_to_string(:not_accepted), do: "You have selected an unacceptable file type"

Для сообщений об ошибках, относящихся ко всем записям, используйте Phoenix.Component.upload_errors/1 и собственную вспомогательную функцию, чтобы вывести понятное сообщение об ошибке:

defp error_to_string(:too_many_files), do: "You have selected too many files"

Отмена записи

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

@impl Phoenix.LiveView
def handle_event("cancel-upload", %{"ref" => ref}, socket) do
  {:noreply, cancel_upload(socket, :avatar, ref)}
end

Обработка загруженных записей

Когда конечный пользователь отправляет форму с live_file_input/1, клиент JavaScript сначала загружает файл или файлы, а затем вызывает обратный вызов для события phx-submit формы.

В обратном вызове для события phx-submit вызовите функцию Phoenix.LiveView.consume_uploaded_entries/3, чтобы обработать завершённые загрузки и сохранить необходимые данные о загруженных файлах вместе с данными формы:

@impl Phoenix.LiveView
def handle_event("save", _params, socket) do
  uploaded_files =
    consume_uploaded_entries(socket, :avatar, fn %{path: path}, _entry ->
      dest = Path.join(Application.app_dir(:my_app, "priv/static/uploads"), Path.basename(path))
      # You will need to create `priv/static/uploads` for `File.cp!/2` to work.
      File.cp!(path, dest)
      {:ok, ~p"/uploads/#{Path.basename(dest)}"}
    end)

  {:noreply, update(socket, :uploaded_files, &(&1 ++ uploaded_files))}
end

Примечание: Доверять метаданным клиента нельзя, однако при загрузке непосредственно на сервер максимальный размер файла проверяется по мере получения каждого фрагмента.

В этом примере файл записывается непосредственно на диск в папку priv. Чтобы получить доступ к загруженному файлу, например в теге <img />, необходимо добавить каталог uploads в static_paths/0. В стандартном проекте Phoenix это находится в lib/my_app_web.ex.

Также следует учитывать, что в режиме разработки изменения в priv/static/uploads будут обнаружены компонентом live_reload. Это означает, что сразу после успешной загрузки приложение будет перезагружено в браузере. Это поведение можно временно отключить, задав code_reloader: false в config/dev.exs.

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

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

Приложение A: UploadLive

Полный пример LiveView из этого руководства:

# lib/my_app_web/live/upload_live.ex
defmodule MyAppWeb.UploadLive do
  use MyAppWeb, :live_view

  @impl Phoenix.LiveView
  def mount(_params, _session, socket) do
    {:ok,
    socket
    |> assign(:uploaded_files, [])
    |> allow_upload(:avatar, accept: ~w(.jpg .jpeg), max_entries: 2)}
  end

  @impl Phoenix.LiveView
  def handle_event("validate", _params, socket) do
    {:noreply, socket}
  end

  @impl Phoenix.LiveView
  def handle_event("cancel-upload", %{"ref" => ref}, socket) do
    {:noreply, cancel_upload(socket, :avatar, ref)}
  end

  @impl Phoenix.LiveView
  def handle_event("save", _params, socket) do
    uploaded_files =
      consume_uploaded_entries(socket, :avatar, fn %{path: path}, _entry ->
        dest = Path.join([:code.priv_dir(:my_app), "static", "uploads", Path.basename(path)])
        # You will need to create `priv/static/uploads` for `File.cp!/2` to work.
        File.cp!(path, dest)
        {:ok, ~p"/uploads/#{Path.basename(dest)}"}
      end)

    {:noreply, update(socket, :uploaded_files, &(&1 ++ uploaded_files))}
  end

  defp error_to_string(:too_large), do: "Too large"
  defp error_to_string(:too_many_files), do: "You have selected too many files"
  defp error_to_string(:not_accepted), do: "You have selected an unacceptable file type"
end

Чтобы получить доступ к загруженным файлам через приложение, обязательно добавьте uploads в MyAppWeb.static_paths/0.

← Предыдущая страница Телеметрия
Следующая страница → Привязки

Пакет Hex Предпросмотр Hex (текущий файл) Посмотреть llms.txt Скачать версию ePub

Создано с помощью ExDoc (v0.40.3) для языка программирования Elixir

© 2014 Chris McCord
Licensed under the MIT License.
https://phoenix-live-view.hexdocs.pm/uploads.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API