"Малокодовый" API пользовательского интерфейса
StippleUI — это библиотека элементов реактивного пользовательского интерфейса для Stipple.jl, эффективного и полнофункционального решения для создания красивых, адаптивных, реактивных, высокопроизводительных интерактивных информационных панелей на чистом языке Julia.
StippleUI
предоставляет более 30 элементов пользовательского интерфейса, включая формы и элементы ввода (кнопка, ползунок, флажок, переключатель, группа переключателей, диапазон), списки, таблицы данных, компоненты более высокого уровня (значки, баннеры, карточки, диалоговые окна, фишки, значки) и элементы макета (строка, столбец, информационная панель, заголовок, пробел) из фреймворка Quasar.
julia> btn("Just do it!", @click(:mybutton), loading = :mybutton) |> println
<q-btn :loading="mybutton" label="Just do it!" v-on:click="mybutton = true"></q-btn>
julia> textfield("Label", :mytext) |> println
<q-input label="Label" v-model="mytext"></q-input>
Компоненты Quasar
В StippleUI определены функции для большинства компонентов Quasar Vue. Имена большинства функций совпадают с именами их аналогов в Quasar, например btn()
для q-btn
, tab()
для q-tab
и т. д. Некоторым функциям для ясности были даны другие имена, например textfield()
для q-input
с текстовым типом и numberfield()
для q-input
с числовым типом. У большинства функций есть именованные позиционные аргументы, которые служат для определения общих атрибутов, например label
или fieldname
. Помимо этого, все функции имеют общую схему вызова для неименованных и именованных аргументов:
-
Если компонент поддерживает содержимое, первый неименованный позиционный аргумент передается в него как содержимое.
-
Любой последующий аргумент, не являющийся массивом, передается в компонент как параметр.
-
Любой неименованный аргумент-массив объединяется и передается как содержимое.
-
Если компонент не поддерживает содержимое, например
btn()
, все неименованные аргументы, кроме массивов, передаются как параметры. (Путем передачи массивов можно определять шаблоны для компонента. Дополнительные сведения см. в документации к Vue.js.) -
Именованные аргументы передаются практически так же, как выражение Julia, за следующими исключениями:
-
__
преобразовывается в-
. -
!
в середине именованного аргумента преобразовывается в.
. -
!
в конце именованного аргумента означает, что его следует рассматривать как выражение JS. -
Если значением именованного аргумента является символ, это означает, что аргумент следует рассматривать как выражение JS.
-
Нестандартные символы, которые не допускаются в именах переменных Julia, можно использовать посредством нотации
var""
, напримерspan(var"v-html" = "My Text with <br>new lines")
-
Большинство имен переменных, содержащих дефис в синтаксисе Vue, заменяются автоматически, например
"leftlabel" => "left-label"
. Все стандартные сопоставления можно найти вStippleUI.API.ATTRIBUTES_MAPPINGS
.
-
Привязки
Присваивать значения свойствам компонентов можно двумя способами:
-
присвоение строкового значения:
attribute = "lorem ipsum"
; -
присвоение выражения JavaScript:
-
путем присвоения
Symbol
-
attribute = :input
;
-
путем добавления символа
!
к атрибуту
attribute! = "input"
.
В большинстве случаев этот синтаксис используется для прямой привязки переменных приложения, но можно привязывать и более сложные выражения, например элементы массива (имейте в виду, что в JS индексация начинается с 0): attribute = Symbol("data[0]")
attribute = R"data[0]"
attribute! = "data[0]"
Строковый макрос R""
— это удобный способ определения символов.
Код JavaScript
Vue.js дает возможность встраивать функции JavaScript, которые вызываются вручную. Они называются методами (methods
). Чтобы добавить метод в приложение, используйте макрос @methods
следующим образом:
@methods begin
"""
logdemo: function(text) {
console.log("Text from Stipple: " + text)
return text
},
squaredemo: function(number) {
console.log("The square of " + number + " is " + number**2)
return number**2
}
"""
end
Метод можно вызвать из кода Julia
@onchange trigger_variable begin
@run raw"this.logdemo('hello world')"
end
или из другого элемента пользовательского интерфейса:
btn("Call the method", @click("this.function()"))
Можно также добавить код, который будет запускаться автоматически при возникновении определенных событий, например watch
, mounted
, created
, computed
. Такой код можно легко определить с помощью соответствующих макросов @watch
, @mounted
, @created
, @computed
, например:
@created """"
console.log('This app has just been created!')
"""
Дополнительные сведения см. в демонстрации редактируемого дерева. Эти макросы также работают с явными моделями, например:
@created MyApp """"
console.log('This app has just been created!')
"""
Пользовательские события
Макрос @event
поддерживает пользовательские события.
@event :uploaded begin
println("Files have been uploaded!")
end
Ниже показан код Julia, который выполняется при перенаправлении события из клиента на сервер. Обычно события в клиенте происходят из определенных компонентов Vue, например q-uploader
. Их можно перенаправлять, вызывая макрос @on
с двумя символьными аргументами.
julia> uploader("Upload files", url = "/upload" , @on(:uploaded, :uploaded))
"<q-uploader url=\"/upload\" v-on:uploaded=\"function(event) { handle_event(event, 'uploaded') }\">Upload files</q-uploader>"
События также можно инициировать вручную, вызывая handle_event(event, 'uploaded')
на стороне клиента.
Дополнительные сведения см. в демонстрации отправки файла. Макрос @event
также работает с явными моделями, например:
@event MyApp :uploaded begin
println("Files have been uploaded to MyApp!")
end
Отсутствующие компоненты
Если компонент Quasar еще не реализован в StippleUI, вы все равно можете использовать функцию quasar()
, чтобы добавить его в пользовательский интерфейс:
julia> quasar(:btn, label = "Action!") |> println
<q-btn label="Action!"></q-btn>
Очень похожим образом можно интегрировать компоненты Vue или любой другой компонент HTML:
julia> vue(:calender, date = "today", "This is still a dream!")
"<vue-calender date=\"today\">This is still a dream!</vue-calender>"
julia> xelem(:br)
"<br></br>"
Использование макетов
Определение макета полезно для задания общей структуры всех страниц, например для добавления панели навигации. Определить макет и передать его в функцию html
можно следующим образом:
function layout()
#именованный аргумент layout принимает строку, поэтому мы объединяем строки HTML
join([head(title("Genie app")),
body([h1("Welcome!"), "<% @yield %>"])])
end
ui() = p("Genie!")
@page("/layout", ui, layout=layout())
Здесь @yield
внедряет содержимое страницы в макет.
Анализ и преобразование кода HTML в код Julia
Совсем недавно появился новый инструмент — StippleUIParser. Он преобразовывает код HTML в соответствующий код Julia и оптимизирует его. Это вспомогательный инструмент для переноса демонстрационного кода из Интернета в приложения Stipple/Genie.
julia> using StippleUI.StippleUIParser
julia> doc_string = """
<template>
<div class="q-pa-md">
<q-scroll-area style="height: 230px; max-width: 300px;">
<div class="row no-wrap">
<div v-for="n in 10" :key="n" style="width: 150px" class="q-pa-sm">
Lorem @ipsum \$dolor sit amet consectetur adipisicing elit.
</div>
<q-btn color=\"primary\" label=\"`Animate to \${position}px`\" @click=\"scroll = true\"></q-btn>
<q-input hint=\"Please enter some words\" v-on:keyup.enter=\"process = true\" label=\"Input\" v-model=\"input\"></q-input>
<q-input hint=\"Please enter a number\" label=\"Input\" v-model.number=\"numberinput\" class=\"q-my-md\"></q-input>
</div>
</q-scroll-area>
</div>
</template>
""";
julia> parse_vue_html(html_string, indent = 2) |> println
template(
Stipple.Html.div(class = "q-pa-md",
scrollarea(style = "height: 230px; max-width: 300px;",
Stipple.Html.div(class = "row no-wrap", [
Stipple.Html.div(var"v-for" = "n in 10", key! = "n", style = "width: 150px", class = "q-pa-sm",
"Lorem @ipsum dolor sit amet consectetur adipisicing elit."
)
btn(raw"`Animate to ${position}px`", color = "primary", var"v-on:click" = "scroll = true")
textfield("Input", :input, hint = "Please enter some words", var"v-on:keyup.enter" = "process = true")
numberfield("Input", :numberinput, hint = "Please enter a number", class = "q-my-md")
])
)
)
)
Тестирование результата анализа
Существует также инструмент test_vue_parsing()
для тестирования успешности анализа:
julia> test_vue_parsing(raw"""<a :hello="I need $$$">asap</a>""") Original HTML string: <a :hello="I need $$$">asap</a> Julia code: a(hello! = raw"I need $$$", "asap" ) Produced HTML: <a :hello="I need $$$"> asap </a>
Он учитывает все особенности синтаксиса привязки и тег сохранения HTML <pre>
.
julia> test_vue_parsing(raw"""<q-test :hello-world="I need $$$"> asap\n or\ntoday <pre>asap\n or\ntoday </pre></q-test>"""; indent = 2) Original HTML string: <q-test :hello-world="I need $$$"> asap\n or\ntoday <pre>asap\n or\ntoday </pre></q-test> Julia code: quasar(:test, var"hello-world" = R"I need $$$", [ "asap\n or\ntoday", pre( "asap\n or\ntoday " ) ]) Produced HTML: <q-test :hello-world="I need $$$"> asap or today <pre> asap or today </pre> </q-test>