您可以在Elm中使用ports與javascript通信以發佈和訂閱兩個方向的事件。讓我們建立一個例子,在其中顯示石匠佈局的圖像列表,點擊圖像將移除它並觸發石工來佈置剩餘的圖像。
由於Elm應用程序會將多種類型的事件發送給javascript,因此我們可以創建一個發送JavaScript的單個端口,然後JavaScript可以採取行動。這些字符串將是我們可以在JavaScript中解釋的命令,以便告訴砌體做某些事情,如"initialize"
和"imageRemoved"
。這個端口還需要一個郵箱,我們可以從Elm內部發送郵件。
masonryMailbox : Signal.Mailbox String
masonryMailbox =
Signal.mailbox ""
port masonryCommands : Signal String
port masonryCommands =
masonryMailbox.signal
由於您使用StartApp
,你可以在你update
功能回到Effects
,讓我們創建一個將郵件發送到該郵箱無論從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
您可以將StartApp
初始化函數像這樣在發送"initialize"
命令:
init =
(initialModel, sendMasonryCommand "initialize")
在update
功能,如果我們有一個RemoveImage String
行動,我們可以發送"imageRemove"
命令的javascript:
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端來聽取t這些事件。如果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.fullscreen()
時,我們必須從javascript方面給信號一個初始值。 JavaScript的變化是:
var app = Elm.fullscreen(Elm.Main, { setMessage: "" });
現在,處理"initialize"
命令的JavaScript塊內,你就可以將起來砌築的layoutComplete
功能將消息發送到這個新的端口。
$grid.on("layoutComplete", function() {
app.ports.setMessage.send("Masonry layout complete!");
});
爲了消耗來自榆樹的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。