Без Макросов: синтаксис строителя View
Если вы и так счастливы с синтаксисом макросом
view!
описываемым до сих пор, мы можете пропустить эту главу. синтаксис описанный в этом разделе всегда доступен, но никогда не обязателен.
По тем или иным причинам, многие разработчики предпочитают избегать макросов. Быть может вам не нравится ограниченная
поддержка со стороны rustfmt
. (Хотя. вам стоит посмотреть на leptosfmt
, это прекрасный инструмент!)
А может, вы беспокоитесь по поводу влияния макросов на время компиляции. Может быть, вы предпочитаете эстетику
чистого синтаксиса Rust, или переключение контекста между HTML-подобным синтаксисом и кодом на Rust вызывает у вас трудности.
Или может вы хотите больше гибкости в том как вы создаёте и манипулируете HTML элементами, чем даёт макрос view
.
Если вы относитесь к одной из этих категорий, синтаксис строителя может вам подойти.
Макрос view
преобразует HTML-подобный синтаксис в набор Rust функций и вызовов методов. Если не хотите
не использовать макрос view
, этот синтаксис можно использовать самостоятельно. А он весьма хорош!
Во-первых, если хотите, можно даже убрать макрос #[component]
: компонент это просто установочная функция,
создающая view
, так что можно просто объявить компонент как простой вызов функции:
pub fn counter(initial_value: i32, step: u32) -> impl IntoView { }
Элементы создаются путём вызова функции одноименной с создаваемым элементом HTML:
p()
Дочерние элементы можно добавлять с помощью .child()
, который принимает одиночный элемент, массив
или кортеж с типами, реализующими IntoView
.
p().child((em().child("Big, "), strong().child("bold "), "text"))
Атрибуты добавляются при помощи метода .attr()
. Он может принимать любые типы, которые можно передавать в
качестве атрибута внутри макроса view
(типы, реализующие IntoAttribute
).
p().attr("id", "foo").attr("data-count", move || count().to_string())
Аналогично, class:
, prop:
, и style:
соотносятся с методами .class()
, .prop()
, и .style()
.
Слушатели событий могут быть добавлены через .on()
. Типизированные события из leptos::ev
предотвращают опечатки
в названиях событий и обеспечивают правильный вывод типов (англ. type inference) в функции обратного вызова.
button()
.on(ev::click, move |_| set_count.update(|count| *count = 0))
.child("Clear")
Много дополнительных методов можно найти в документации к
HtmlElement
, включая некоторые методы, недоступные напрямую в макросеview
.
Всё это складывается в очень Rust'овый синтаксис для построения полнофункциональных представлений, если вы предпочитаете этот стиль.
/// A simple counter view.
// A component is really just a function call: it runs once to create the DOM and reactive system
pub fn counter(initial_value: i32, step: u32) -> impl IntoView {
let (count, set_count) = create_signal(0);
div().child((
button()
// typed events found in leptos::ev
// 1) prevent typos in event names
// 2) allow for correct type inference in callbacks
.on(ev::click, move |_| set_count.update(|count| *count = 0))
.child("Clear"),
button()
.on(ev::click, move |_| set_count.update(|count| *count -= 1))
.child("-1"),
span().child(("Value: ", move || count.get(), "!")),
button()
.on(ev::click, move |_| set_count.update(|count| *count += 1))
.child("+1"),
))
}
У этого также есть преимущество большей гибкости: поскольку всё это простые Rust функции и методы, их проще использовать в таких вещах, как адаптеры итераторов без какой-либо дополнительной "магии': it’s easier to use them in things like iterator adapters without any additional “magic”:
// take some set of attribute names and values
let attrs: Vec<(&str, AttributeValue)> = todo!();
// you can use the builder syntax to “spread” these onto the
// element in a way that’s not possible with the view macro
let p = attrs
.into_iter()
.fold(p(), |el, (name, value)| el.attr(name, value));
Примечание о производительности
Одно предостережение: макрос
view
применяет значительные оптимизации в режиме сервере рендеринга (SSR), чтобы значительно улучшить производительность рендеринга HTML (в 2-4 раза быстрее, зависит от характеристик приложения). Он делает это путём анализаview
во время компиляции и превращения статических частей в простые HTML строки, вместо синтаксиса строителя.Из этого следуют две вещи:
- Синтаксис строителя и макрос
view
не стоит мешать вовсе или мешать, но очень осторожно: по меньшей мере в режиме SSR c выводом макросаview
стоит обходиться как с "черным ящиком", к которому нельзя применять дополнительные методы строителя не вызывая несоответствий.- Использование синтаксиса строителя выльется в производительность SSR ниже оптимальной. Медленно не будет ни в коем случае (всё равно стоит сделать собственные замеры производительные), но медленнее чем версия оптимизированная макросом
view
.