【问题标题】:Retrieving a DOM value from Elm ports从 Elm 端口检索 DOM 值
【发布时间】:2018-06-30 06:07:37
【问题描述】:

我的 elm 应用程序使用自动滚动功能,它获取元素的 Y 位置并使用Dom.Scroll.toY 在那里滚动。

两个这样做,我设置了两个端口;订阅和发件人。

ports.elm

port setYofElementById : Maybe String -> Cmd msg
port getYofElementById : (Value -> msg) -> Sub msg

index.html

app.ports.setYofElementById.subscribe(function(id) {
  var element = document.getElementById(id);
  var rect = element.getBoundingClientRect();
  app.ports.getYofElementById.send({"number": rect.top});
})

监听器是订阅

subscriptions : Model -> Sub Msg
subscriptions model =
    Ports.getYofElementById getYofElementById

getYofElementById : Decode.Value -> Msg
getYofElementById value =
    let
        result =
            Decode.decodeValue bSimpleIntValueDecoder value
    in
    case result of
        Ok simpleIntValue ->
            SetSelectedElementYPosition (Just simpleIntValue.number)

        Err id ->
            SetSelectedElementYPosition Nothing

SetSelectedElementYPosition 只是设置模型。

现在,执行此操作的操作做了两件事:调用 Port.setYofElementById,然后滚动到模型中的 Y 值,假设它已经设置好了。

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of

        ScrollToY idString ->
            model
                => Cmd.batch
                    [ Ports.setYofElementById (Just idString)
                    , Task.attempt (always NoOp) <| Dom.Scroll.toY "ul" model.selectedElementYPosition
                    ]

但是,这不会按顺序发生。当动作第一次触发时,什么也没有发生。如果我再次触发它,它会滚动到第一个动作中要求的位置。所以它似乎在设置值之前调用了Dom.Scroll.toY

有没有办法强制ScrollToY 中的Cmds 依次发生?还是有更好的方法来做到这一点?

【问题讨论】:

    标签: elm


    【解决方案1】:

    您可以让Cmds 按顺序执行,方法是让第二个,即执行Dom.Scroll.toY 的那个,作为对第一个执行setYofElementById 的响应的响应。下面的更新函数实现了这一点:

    update : Msg -> Model -> ( Model, Cmd Msg )
    update msg model =
        case msg of
            ScrollToY idString ->
                (model, Ports.setYofElementById idString)
            SetSelectedElementYPosition (Just newY) -> 
                (model, Task.attempt (always NoOp) <| Dom.Scroll.toY "ul" newY)
            SetSelectedElementYPosition Nothing -> 
                (model, Cmd.none)
            NoOp -> 
                (model, Cmd.none)
    

    Cmds 正确排序后,您需要确保Dom.Scroll.toYnewY 参数位于正确的参考框架中,以获得您想要的效果。

    【讨论】:

    • 测序是关键。没有办法(我认为)相对于使端口调用从 elm 到 js 的初始操作对滚动操作进行排序,这是一个违反直觉的大障碍;它只能相对于订阅来完成,因为它们是不同的因果分支。看我的回答。
    【解决方案2】:

    我终于通过将Task.attempt (always NoOp) &lt;| Dom.Scroll.toY "ul" model.selectedElementYPosition 的操作附加到 订阅 调用的操作而不是操作上来实现此功能。这才是关键。

    对于端口,subscribesend 操作遵循完全不同的路径,因此从 js 到 elm 对​​ send 做出反应的任何内容都不会在从 elm 到 js 的操作中被引用。

    在这种情况下,由于从订阅中调用SetSelectedElementYPosition,因此您必须在此处设置更新:

        SetSelectedElementYPosition idString ->
           ({model | selectedElementYPosition = number }, Cmd.none)
                |> andThen update GoToSelectedElementYPosition
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多