Engee 文档

条纹

    mutable struct Reactive{T} <: Observables.AbstractObservable{T}

Reactive 是由模型处理的变量的基本类型。它是一个`AbstractObservable` ,其内容可通过在`Reactive` 变量名后追加`[]` 来获得。为方便起见,Reactive 可缩写为`R` 。

创建 Reactive 变量有几种方法:

  • r = Reactive(8)

  • r = Reactive{Float64}(8)

  • r = Reactive{Float64}(8, READONLY)

  • r = Reactive{String}("Hello", PRIVATE)

  • r = Reactive(jsfunction"console.log('Hi')", JSFUNCTION)

type ReactiveModel

Stipple 模型继承的抽象类型。Stipple 模型用于在 Julia 后端和 JavaScript/Vue.js 前端之间自动进行双向数据同步和数据交换。

示例

Base.@kwdef mutable struct HelloPie <: ReactiveModel
  plot_options::R{PlotOptions} = PlotOptions(chart_type=:pie, chart_width=380, chart_animations_enabled=true,
                                            stroke_show = false, labels=["Slice A", "Slice B"])
  piechart::R{Vector{Int}} = [44, 55]
  values::R{String} = join(piechart, ",")
end
function render

抽象函数。需要由插件进行专门处理。Stipple 会自动调用该函数,将 Julia 数据类型(与`ReactiveModel` 实例中的字段相对应)序列化为 JavaScript/JSON。一般来说,专用方法应返回 Julia`Dict` ,并由`Stipple` 自动进行 JSON 编码。如果需要对生成的`Dict` 中的某些类型进行自定义 JSON 序列化,则应针对特定类型专用`JSON.lower` 。

示例

function Stipple.render(ps::PlotSeries, fieldname::Union{Symbol,Nothing} = nothing)
  Dict(:name => ps.name, ps.plotdata.key => ps.plotdata.data)
end

Specialized JSON rendering for Undefined

JSON.lower(x::Undefined) = "__undefined__"
function update! :: {M<:ReactiveModel}

抽象函数,用于根据前台数据更新`ReactiveModel` 中的字段值。可以针对专用类型进行专门处理,但通常没有必要。如果专门化,则必须返回作为第一个参数提供的`ReactiveModel` 的更新实例。

示例

function update!(model::M, field::Any, newval::T, oldval::T)::M where {T,M<:ReactiveModel}
  setfield!(model, field, newval)

  model
end
function watch

抽象函数。可被插件用于定义自定义的 Vue.js 监视函数。

function js_methods(app::T) where {T<:ReactiveModel}

为 vue 元素的`methods` 部分定义 js 函数。函数的预期结果类型为

  • String 包含 javascript 代码

  • Pair 的函数名和函数代码

  • Function 返回 javascript 代码字符串

  • Dict 函数名和函数代码的字符串

  • VectorExample 1

js_methods(::MyDashboard) = """
  mysquare: function (x) {
    return x^2
  }
  myadd: function (x, y) {
    return x + y
  }
"""

Example 2

js_methods(::MyDashboard) = Dict(:f => "function(x) { console.log('x: ' + x) })

Example 3

js_greet() = :greet => "function(name) {console.log('Hello ' + name)}"
js_bye() = :bye => "function() {console.log('Bye!')}"
js_methods(::MyDashboard) = [js_greet, js_bye]
function js_computed(app::T) where {T<:ReactiveModel}

定义 vue 元素`computed` 部分的 js 函数。每次内部参数的值发生变化时,这些属性都会更新。函数的预期结果类型为

  • String 包含 javascript 代码

  • Pair 的函数名和函数代码

  • Function 返回 javascript 代码字符串

  • Dict 函数名和函数代码的字符串

  • Vector

示例

js_computed(app::MyDashboard) = """
  fullName: function () {
    return this.firstName + ' ' + this.lastName
  }
"""
function js_watch(app::T) where {T<:ReactiveModel}

为 vue 元素的`watch` 部分定义 js 函数。每次相应属性发生变化时,都会调用这些函数。函数的预期结果类型为

  • String 包含 javascript 代码

  • Pair 的函数名和函数代码

  • Function 返回 javascript 代码字符串

  • Dict 函数名和函数代码的字符串

  • Vector

示例

每次`firstName` 或`lastName` 发生变化时,都会更新`fullName` 。

js_watch(app::MyDashboard) = """
  firstName: function (val) {
    this.fullName = val + ' ' + this.lastName
  },
  lastName: function (val) {
    this.fullName = this.firstName + ' ' + val
  }
"""
function js_created(app::T)::Union{Function, String, Vector} where {T<:ReactiveModel}

定义 vue 元素`created` 部分的 js 语句。

函数的结果类型可以是

  • String 包含 javascript 代码

  • Function 返回 javascript 代码字符串

  • Vector 的字符串 Example 1

js_created(app::MyDashboard) = """
    if (this.cameraon) { startcamera() }
"""

Example 2

startcamera() = "if (this.cameraon) { startcamera() }"
stopcamera() = "if (this.cameraon) { stopcamera() }"

js_created(app::MyDashboard) = [startcamera, stopcamera]

检查结果的方法如下

julia> render(MyApp())[:created]
JSONText("function(){
    if (this.cameraon) { startcamera() }

    if (this.cameraon) { stopcamera() }
}")
function js_mounted(app::T)::Union{Function, String, Vector} where {T<:ReactiveModel}

定义 vue 元素`mounted` 部分的 js 语句。

函数的结果类型可以是

  • String 包含 javascript 代码

  • Function 返回 javascript 代码字符串

  • Vector 的字符串 Example 1

js_mounted(app::MyDashboard) = """
    if (this.cameraon) { startcamera() }
"""

Example 2

startcamera() = "if (this.cameraon) { startcamera() }"
stopcamera() = "if (this.cameraon) { stopcamera() }"

js_mounted(app::MyDashboard) = [startcamera, stopcamera]

检查结果的方法如下

julia> render(MyApp())[:mounted]
JSONText("function(){
    if (this.cameraon) { startcamera() }

    if (this.cameraon) { stopcamera() }
}")
function client_data(app::T)::String where {T<:ReactiveModel}

定义仅浏览器可见的附加数据。

它用于保存不稳定的数据,例如需要先通过验证的表单数据。为了使用这些数据,您可能还需要定义 js_methods

示例

import Stipple.client_data
client_data(m::Example) = client_data(client_name = js"null", client_age = js"null", accept = false)

将为模型`Example` 定义附加字段`client_name` 、client_age 和`accept` 。当然,这些字段不应与模型的现有字段重叠。

function register_components(model::Type{M}, keysvals::AbstractVector) where {M<:ReactiveModel}

用于添加需要在 Vue.js 应用程序中注册的 Vue 组件的实用程序。在注册 Stipple 插件提供的组件时通常需要使用该函数。

示例

Stipple.register_components(HelloPie, StippleCharts.COMPONENTS)
function components(m::Type{M})::String where {M<:ReactiveModel}
function components(app::M)::String where {M<:ReactiveModel}

ReactiveModel M 注册的 Vue.js 组件的 JSON 表示形式。

setindex_withoutwatchers!(field::Reactive, val; notify=(x)->true)
setindex_withoutwatchers!(field::Reactive, val, keys::Int...; notify=(x)->true)

在不触发监听器的情况下更改反应式字段的内容。如果指定了键,则只有这些侦听器可以免于触发。

setfield_withoutwatchers!(app::ReactiveModel, field::Symmbol, val; notify=(x)->true)
setfield_withoutwatchers!(app::ReactiveModel, field::Symmbol, val, keys...; notify=(x)->true)

更改 ReactiveModel 的字段而不触发监听器。如果指定了键,则只有这些侦听器免于触发。

function init(::Type{M};
                vue_app_name::S = Stipple.Elements.root(M),
                endpoint::S = vue_app_name,
                channel::Union{Any,Nothing} = nothing,
                debounce::Int = JS_DEBOUNCE_TIME,
                transport::Module = Genie.WebChannels,
                core_theme::Bool = true)::M where {M<:ReactiveModel, S<:AbstractString}

通过设置与 Vue.js 前端集成的自定义 JavaScript 来初始化模型`M` 的反应性,并执行后端与前端的双向数据同步。返回模型实例。

示例

hs_model = Stipple.init(HelloPie)
function setup(model::M, channel = Genie.config.webchannels_default_route)::M where {M<:ReactiveModel}

为模型的反应属性配置反应处理程序。内部调用。

Base.push!(app::M, vals::Pair{Symbol,T}; channel::String,
            except::Union{Genie.WebChannels.HTTP.WebSockets.WebSocket,Nothing,UInt}) where {T,M<:ReactiveModel}

通过`channel` 广播`vals` ,将数据有效载荷推送到前端。

function rendering_mappings(mappings = Dict{String,String})

将额外的`mappings` 注册为 Julia 到 Vue 属性映射(例如`foobar` 到`foo-bar` )。

function julia_to_vue(field, mapping_keys = mapping_keys())

将 Julia 名称转换为 Vue 名称(例如,将`foobar` 转换为`foo-bar` )。

function parse_jsfunction(s::AbstractString)

检查字符串是否是一个有效的 js 函数,并返回一个`Dict` ,后台的 reviver 函数可据此构建一个函数。

function replace_jsfunction!(js::Union{Dict, JSONText})

将包含有效 js 函数的所有 JSONText 值替换为`Dict` ,该 为 reviver 函数编码。对于 JSONText 变量,它会将 dict 封装在 JSONText 中,使函数类型保持稳定。

替换输入内容副本上的所有 JSONText 值,请参见 replace_jsfunction!.

function deps(channel::String = Genie.config.webchannels_default_route)

输出在页面中注入依赖项所需的 HTML 代码(页面中的

创建一个与 vue 组件的字段绑定的 js 表达式。从内部看,这只不过是转换为符号,但它是创建带空格符号的简短版本。

示例

julia> btn("", @click("toggleFullscreen"), icon = R"is_fullscreen ? 'fullscreen_exit' : 'fullscreen'")
"<q-btn label v-on:click="toggleFullscreen" :icon="is_fullscreen ? 'fullscreen_exit' : 'fullscreen'"></q-btn>"

注意:对于只包含变量名的表达式,我们建议使用符号符号表示法

julia> btn("", @click("toggleFullscreen"), icon = :fullscreen_icon)
"<q-btn label v-on:click="toggleFullscreen" :icon="fullscreen_icon"></q-btn>"
on(f, observable::AbstractObservable; weak = false, priority=0, update=false)::ObserverFunction

将函数`f` 添加为`observable` 的监听器。每当观察值 的值通过`observable[] = val` 被设置,f 就会被`val` 调用。

返回一个封装了`f` 和`observable` 的`ObserverFunction` ,并允许通过调用`off(observerfunction)` 而不是`off(f, observable)` 来轻松断开连接。如果想从一个旧的`Observable` 计算出一个新的 ,请使用`map(f, ::Observable)` 。

如果设置了`weak = true` ,一旦返回的`ObserverFunction` 不再被任何地方引用并被垃圾回收,新连接就会被删除。如果某个父对象与外部可观察对象建立连接,并存储由此产生的`ObserverFunction` 实例,这将非常有用。然后,一旦该父对象被垃圾回收,弱可观察对象连接就会自动移除。

示例

julia> obs = Observable(0)
Observable(0)

julia> on(obs) do val
           println("current value is ", val)
       end
ObserverFunction defined at REPL[17]:2 operating on Observable(0)
julia> obs[] = 5;
current value is 5

我们还可以给回调设置优先级,这样就可以在调用其他回调之前或之后调用特定的回调,而不受注册顺序的影响。优先级最高的回调会被优先调用,默认值为 0,可以使用整个 Int 范围。因此可以这样做

julia> obs = Observable(0)
julia> on(obs; priority=-1) do x
           println("Hi from first added")
       end
julia> on(obs) do x
           println("Hi from second added")
       end
julia> obs[] = 2
Hi from second added
Hi from first added

如果设置`update=true` ,on 将立即调用 f(obs[]):

julia> on(Observable(1); update=true) do x
    println("hi")
end
hi
onbutton(f::Function, button::R{Bool}; async = false, weak = false)

将函数与反应布尔参数(通常代表应用程序的一个按钮)相连。函数调用后,参数会被设置为 false。async 关键字指定调用是否应同步进行。

示例

onbutton(model.save_button) do
  # save what has to be saved
end
@js_str -> JSONText

构建一个 JSONText,如`js"button=false"` ,无需插值和取消转义(引号除外`“ ,仍需转义)。避免转义`”可以通过js"""alert("Hello World")"" 来实现。

@kwredef(expr)

开发过程中的辅助函数,可一对一替代`@kwdef` ,但允许重新定义结构体。

它在内部定义了一个新的结构体,并在原结构体名称后附加了一个数字,然后将该结构体赋值给一个具有原结构体名称的变量。

Stipple.@kwdef

模型定义的辅助函数,可一对一地替代`Base.@kwdef` 。

当`Genie.Configuration.isprod() == true` 时,该宏调用`@kwredef` 并允许重新定义模型。否则,它将调用`Base.@kwdef` 。