【问题标题】:Elm + Masonry.js榆树 + Masonry.js
【发布时间】:2016-03-02 04:55:58
【问题描述】:

我正在尝试通过端口将 Elm 应用程序与 Masonry.js 集成,但我无法弄清楚如何让 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 的实际呈现。

【问题讨论】:

    标签: masonry elm


    【解决方案1】:

    您可以在 Elm 中使用 ports 与 javascript 进行通信,以便双向发布和订阅事件。让我们构建一个示例,其中显示带有 masonry 布局的图像列表,单击图像将删除它并触发 masonry 来布局剩余的图像。

    由于 Elm 应用程序将向 javascript 发送多种类型的事件,我们可以创建一个单独的端口来发送字符串,然后 javascript 可以对其进行操作。这些字符串将是我们可以在 javascript 中解释的命令,以便告诉 masonry 执行某些操作,例如 "initialize""imageRemoved"。这个端口还需要一个邮箱,我们可以从 Elm 内部向该邮箱发送消息。

    masonryMailbox : Signal.Mailbox String
    masonryMailbox =
      Signal.mailbox ""
    
    port masonryCommands : Signal String
    port masonryCommands =
      masonryMailbox.signal
    

    由于您使用的是StartApp,因此您可以在update 函数中返回Effects,因此让我们创建一个函数,该函数将从StartApp 初始化程序和@987654331 内部向此邮箱发送消息@函数。

    sendMasonryCommand : String -> Effects.Effects Action
    sendMasonryCommand cmd =
      let
        task =
          Signal.send masonryMailbox.address cmd
            `Task.andThen` \_ -> Task.succeed NoOp
      in
        Effects.task task
    

    您可以像这样在StartApp init 函数期间发送"initialize" 命令:

    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" 命令,我们可以告诉masonry 再次触发布局命令。

    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 块中,您可以连接masonry 的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

    【讨论】:

      猜你喜欢
      • 2017-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多