Spec-Zone.ru › Phoenix

Компоненты и HEEx

Исходный код

Требование: предполагается, что вы ознакомились с вводными руководствами и запустили приложение Phoenix.

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

Конвейер конечной точки Phoenix принимает запрос, направляет его контроллеру и вызывает модуль представления для отображения шаблона. Интерфейс представления со стороны контроллера прост: контроллер вызывает функцию представления с назначенными значениям соединения, а задача этой функции — вернуть шаблон HEEx. Любую функцию, которая принимает параметр assigns и возвращает шаблон HEEx, мы называем функциональным компонентом.

Фреймворк Phoenix предназначен для HTML-приложений, JSON API, конечных точек GraphQL и т. д. Поэтому все возможности, связанные с отображением HTML, входят в состав двух отдельных пакетов:

  • phoenix_html — определяет строительные блоки для безопасного создания HTML. В проекте вы будете главным образом взаимодействовать с модулем Phoenix.HTML, который импортируется по умолчанию во все шаблоны

  • phoenix_live_view — библиотека для создания насыщенных интерактивных интерфейсов реального времени на основе HTML, отображаемого на сервере. LiveView предоставляет несколько абстракций для создания совместных и динамических приложений, а также определяет язык шаблонов HEEx, функциональные компоненты и JS-команды, предлагая мощные абстракции для любых приложений с HTML, отображаемым на сервере

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

Функциональные компоненты

Функциональные компоненты — основа любого отображения шаблонов на основе разметки в Phoenix. Они служат общей абстракцией для стандартных приложений с контроллерами MVC, приложений LiveView, макетов и небольших элементов интерфейса, используемых в других шаблонах. Их документация доступна в модуле Phoenix.Component.

В конце главы о жизненном цикле запроса мы создали шаблон в lib/hello_web/controllers/hello_html/show.html.heex. Откроем его:

<Layouts.app flash={@flash}>
  <section>
    <h2>Hello World, from {@messenger}!</h2>
  </section>
</Layouts.app>

<Layouts.app> — это функциональный компонент, определённый внутри lib/hello_web/components/layouts.ex. Если открыть этот файл, вы увидите:

  def app(assigns) do
    ~H"""
    <header class="navbar px-4 sm:px-6 lg:px-8">
    ...

До сих пор все определённые нами функциональные компоненты также могли использоваться как шаблоны. Давайте узнаем о них больше и определим собственный компонент, чтобы инкапсулировать HTML-разметку.

Представим, что мы хотим переработать show.html.heex и вынести отображение <h2>Hello World, from {@messenger}!</h2> в отдельную функцию. Помните, что show.html.heex встроен в модуль HelloHTML. Откроем его:

defmodule HelloWeb.HelloHTML do
  use HelloWeb, :html

  embed_templates "hello_html/*"
end

Всё довольно просто. Всего две строки: use HelloWeb, :html. Эта строка вызывает функцию html/0, определённую в HelloWeb, которая настраивает базовые импорты и конфигурацию для наших функциональных компонентов и шаблонов. Все импорты и псевдонимы в нашем модуле также будут доступны в шаблонах. Аналогично, если мы хотим написать функциональный компонент, который будет вызываться из show.html.heex, достаточно добавить его в HelloHTML. Давайте так и сделаем:

defmodule HelloWeb.HelloHTML do
  use HelloWeb, :html

  embed_templates "hello_html/*"

  attr :messenger, :string, required: true

  def greet(assigns) do
    ~H"""
    <h2>Hello World, from {@messenger}!</h2>
    """
  end
end

С помощью макроса Phoenix.Component.attr/3 мы объявили принимаемые атрибуты, а затем определили функцию greet/1, возвращающую шаблон HEEx.

Теперь нужно обновить show.html.heex:

<Layouts.app flash={@flash}>
  <section>
    <.greet messenger={@messenger} />
  </section>
</Layouts.app>

После перезагрузки http://localhost:4000/hello/Frank мы должны увидеть то же содержимое, что и раньше! Теперь show.html.heex вызывает два разных функциональных компонента:

  • <Layouts.app — синтаксис вызова функциональных компонентов, определённых в отдельном модуле; он подчиняется тем же правилам, что и вызов любой другой функции в Elixir

  • <.greet — если функциональный компонент определён в том же модуле, что и шаблон, имя модуля можно опустить и вызвать компонент, добавив точку перед его именем

Поскольку шаблон show.html.heex встроен в модуль HelloHTML, мы смогли вызвать функциональный компонент напрямую как <.greet messenger="..." />. Если бы компонент был определён в другом месте, пришлось бы указать его полное имя, например: <HelloWeb.HelloHTML.greet messenger="..." />.

Если объявить атрибуты обязательными, Phoenix предупредит, если мы вызовем компонент <.greet />, не передав атрибуты. Если атрибут необязательный, можно указать параметр :default со значением:

attr :messenger, :string, default: nil

В целом функциональные компоненты — основа системы отображения Phoenix. Теперь разберёмся во всех возможностях языка шаблонов HEEx.

HEEx

Функциональные компоненты и файлы шаблонов используют язык шаблонов HEEx, название которого расшифровывается как «HTML + Embedded Elixir». Мы можем писать код Elixir внутри {...} для интерполяции с учётом HTML в атрибутах тегов и теле документа, как мы делали выше. Например, с помощью @name мы обращаемся к ключу name, определённому внутри assigns.

Также можно интерполировать произвольные блоки HEEx с помощью <%= ... %>. Это часто используют для блочных конструкций. Например, для условных выражений:

<%= if some_condition? do %>
  <p>Some condition is true for user: {@messenger}</p>
<% else %>
  <p>Some condition is false for user: {@messenger}</p>
<% end %>

или даже циклов:

<table>
  <tr>
    <th>Number</th>
    <th>Power</th>
  </tr>
  <%= for number <- 1..10 do %>
    <tr>
      <td>{number}</td>
      <td>{number * number}</td>
    </tr>
  <% end %>
</table>

В HEEx также есть удобные расширения HTML, которые мы рассмотрим далее.

Расширения HTML

Помимо интерполяции выражений Elixir, шаблоны .heex поддерживают расширения с учётом HTML. Например, посмотрим, что произойдёт, если попытаться интерполировать значение с символами «<» или «>», что может привести к внедрению HTML:

{"<b>Bold?</b>"}

После отображения шаблона на странице вы увидите буквальный текст <b>. Это означает, что пользователи не могут внедрить HTML-содержимое на страницу. Если вы хотите разрешить им это, можно вызвать raw, но будьте крайне осторожны:

{raw("<b>Bold?</b>")}

Ещё одна мощная возможность шаблонов HEEx — проверка HTML и синтаксиса интерполяции атрибутов. Можно написать:

<div title="My div" class={@class}>
  <p>Hello {@username}</p>
</div>

Обратите внимание, что можно просто использовать key={value}. HEEx автоматически обработает особые значения, например false, чтобы удалить атрибут, а также списки классов.

Чтобы интерполировать динамическое число атрибутов из списка ключевых слов или карты, используйте:

<div title="My div" {@many_attributes}>
  <p>Hello {@username}</p>
</div>

Попробуйте также удалить закрывающий </div> или переименовать его в </div-typo>. Шаблоны HEEx сообщат об ошибке.

HEEx также поддерживает сокращённый синтаксис для выражений if и for с помощью специальных атрибутов :if и :for. Например, вместо такого варианта:

<%= if @some_condition do %>
  <div>...</div>
<% end %>

можно написать:

<div :if={@some_condition}>...</div>

Аналогично, выражения comprehensions можно записать так:

<ul>
  <li :for={item <- @items}>{item.name}</li>
</ul>

CoreComponents

В новом приложении Phoenix в папке components также будет модуль core_components.ex. Это отличный пример определения функциональных компонентов для повторного использования во всём приложении. Благодаря этому по мере развития приложения компоненты будут выглядеть единообразно.

Если заглянуть в def html в HelloWeb, размещённый в lib/hello_web.ex, вы увидите, что CoreComponents автоматически импортируются во все HTML-представления через use HelloWeb, :html. Поэтому в самом CoreComponents используется use Phoenix.Component, а не use HelloWeb, :html в начале файла: второй вариант привёл бы к взаимной блокировке, поскольку мы попытались бы импортировать CoreComponents в сам модуль.

CoreComponents также играют важную роль в генераторах кода Phoenix, поскольку генераторы предполагают наличие этих компонентов, чтобы быстро создавать заготовки приложения. Чтобы подробнее ознакомиться со всеми этими возможностями, вы можете:

  • Изучить сгенерированный модуль CoreComponents и ознакомиться с практическими примерами

  • Прочитать официальную документацию по Phoenix.Component

  • Прочитать официальную документацию по HEEx и сигилам ~H

  • Если вам нужны более высокоуровневые компоненты, чем минимальный набор, включённый в Phoenix, проект LiveView ведёт список систем компонентов

Макеты

При обсуждении компонентов и отображения в Phoenix важно понимать концепцию макетов.

Во всех приложениях Phoenix есть компонент, называемый «корневым макетом». Именно здесь находятся теги <head> и <body> HTML-страницы. Корневой макет настраивается в файле lib/hello_web/router.ex:

  plug :put_root_layout, html: {HelloWeb.Layouts, :root}

В только что сгенерированном приложении шаблон находится в lib/hello_web/components/layouts/root.html.heex. Откройте его и ближе к концу <body> вы увидите следующее:

{@inner_content}

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

Любая динамическая функциональность приложения реализуется в виде функциональных компонентов. Например, меню приложения и боковая панель обычно входят в компонент app в lib/hello_web/components/layouts.ex, который вызывается в каждом шаблоне:

<Layouts.app flash={@flash}>
  ...
</Layouts.app>

Этот механизм также очень гибок. Например, чтобы создать макет для администратора, достаточно добавить новую функцию в модуль Layouts, а затем вызвать Layouts.admin вместо Layouts.app:

<Layouts.admin flash={@flash}>
  ...
</Layouts.admin>

В предыдущих версиях Phoenix использовался механизм вложенных макетов: :layouts передавался в Phoenix.Controller, а :layout — в Phoenix.LiveView. В новых приложениях Phoenix этот механизм не рекомендуется.

← Предыдущая страница Контроллеры
Следующая страница → Ecto

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

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

© 2014 Chris McCord
Licensed under the MIT License.
https://phoenix.hexdocs.pm/components.html

Spec-Zone.ru

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