我正在尝试通过端口与Masonry.js集成一个Elm应用程序但是我无法弄清楚如何获取Signal Html来触发告诉Masonry.js重绘视图的端口。
我正在使用StartApp,我不知道如何从更新调用中获取视图已完成重新呈现的信号。
可以使用Elm或完全Elm解决方案更好地工作的替代库也将受到赞赏。
有关我正在尝试解决的整体问题的更多详细信息: 我有一系列图像,我想以砖石格式(http://masonry.desandro.com/)进行平铺。它们由Elm中的对象列表表示,它们被转换为视图中的div列表(适当地设置了背景图像),但是图像具有不同的大小,因此希望很好地平铺它们。我正在使用StartApp(http://package.elm-lang.org/packages/evancz/start-app/2.0.2/)来抽象html的实际呈现。
答案 0 :(得分:7)
您可以在Elm中使用ports与javascript通信,以便在两个方向上发布和订阅活动。让我们构建一个示例,其中图像列表以砖石布局显示,单击图像将删除它并触发砌体布局剩余图像。
由于Elm应用程序会向javascript发送多种类型的事件,我们可以创建一个发送字符串的单个端口,javascript随后可以对其进行操作。这些字符串将是我们可以在javascript中解释的命令,以告诉砌体执行某些操作,例如"initialize"
和"imageRemoved"
。此端口还需要一个邮箱,我们可以从Elm内部发送邮件。
masonryMailbox : Signal.Mailbox String
masonryMailbox =
Signal.mailbox ""
port masonryCommands : Signal String
port masonryCommands =
masonryMailbox.signal
由于您正在使用StartApp
,因此您可以在Effects
功能中返回update
,因此我们要创建一个功能,将邮件发送到此邮箱StartApp
初始值设定项和update
函数内部。
sendMasonryCommand : String -> Effects.Effects Action
sendMasonryCommand cmd =
let
task =
Signal.send masonryMailbox.address cmd
`Task.andThen` \_ -> Task.succeed NoOp
in
Effects.task task
您可以在"initialize"
初始化函数期间发送StartApp
命令,如下所示:
init =
(initialModel, sendMasonryCommand "initialize")
在update
函数中,如果我们有RemoveImage String
操作,我们可以向javascript发送"imageRemove"
命令:
update action model =
case action of
NoOp ->
(model, Effects.none)
RemoveImage url ->
let model' =
{ model
| images = List.filter ((/=) url) model.images
, message = "Removing image " ++ url
}
in (model', sendMasonryCommand "imageRemoved")
现在我们需要连接javascript方面来监听这些事件。如果javascript获得命令"initialize"
,那么我们可以连接砌体。如果我们得到"imageRemoved"
命令,我们可以告诉砌体再次触发布局命令。
var app = Elm.fullscreen(Elm.Main);
app.ports.masonryCommands.subscribe(function(cmd) {
var $grid = $('.grid')
if (cmd === "initialize") {
$grid.masonry({
itemSelector: '.grid-item',
percentPosition: true,
columnWidth: '.grid-sizer'
});
$grid.imagesLoaded().progress( function() {
$grid.masonry();
});
} else if (cmd === "imageRemoved") {
$grid.masonry();
}
});
我们还可以连接端口以将事件发送回Elm。每次砌体完成渲染时,让我们通过向Elm发送消息来添加示例。首先,我们将创建一个名为setMessage
的端口。
port setMessage : Signal String
由于这是javascript将发布到的端口,我们只在Elm中定义函数签名,而不是函数本身。相反,当我们调用Elm.fullscreen()
时,我们必须从javascript端给出信号的初始值。 javascript更改为:
var app = Elm.fullscreen(Elm.Main, { setMessage: "" });
现在,在处理"initialize"
命令的javascript块内,您可以连接砌体的layoutComplete
函数以向此新端口发送消息。
$grid.on("layoutComplete", function() {
app.ports.setMessage.send("Masonry layout complete!");
});
要从Elm中的setMessage
端口使用这些消息,您需要SetMessage String
操作,并且您需要在StartApp
内映射信号} inputs
列表。您的StartApp
初始值设定项代码如下所示:
app =
StartApp.start
{ init = init
, view = view
, update = update
, inputs = [ Signal.map SetMessage setMessage ]
}
我在几个要点中提供了所有这些的完整工作示例。这是一个gist containing the Elm code,这里是gist containing the html and javascript。