2016-03-02 63 views
2

我試圖通過端口獲得與Masonry.js集成的Elm應用程序,但是我試圖找出如何獲取Signal Html來觸發告知Masonry.js的端口重新繪製視圖。Elm + 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的實際呈現。

回答

7

您可以在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行動,你將需要將信號映射StartAppinputs名單內。你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