从Elm端口检索DOM值

时间:2018-01-21 13:55: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

有没有办法强制Cmd中的ScrollToY按顺序发生?或者有更好的方法来做到这一点吗?

2 个答案:

答案 0 :(得分:5)

你可以让Cmd顺序执行,让第二个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) 。 }。以下更新功能可以实现此目的:

Cmd

newY s正确排序后,您需要确保Dom.Scroll.toY的{​​{1}}参数位于正确的参照系中,以获得您想要的效果。< / p>

答案 1 :(得分:2)

我终于通过将Task.attempt (always NoOp) <| Dom.Scroll.toY "ul" model.selectedElementYPosition的操作添加到订阅调用的操作而非操作来实现此目的。这是关键。

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

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

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