如何在 Elm 中自动滚动到 div 的底部
How to auto-scroll to the bottom of a div in Elm
我将 <div>
s 添加到包装器 <div>
并且我需要能够滚动到每次添加的最后一个。我如何在 Elm 中执行此操作?
<div class="messages" style="height: 7em; overflow: scroll">
<div>Anonymous: Hello</div>
<div>John: Hi</div>
</div>
直觉上,我似乎可以调用 运行 的 JavaScript 代码 element.scrollTop = element.scrollHeight
:
AddChatMessage chatMessage ->
( { model | chatMessages = model.chatMessages ++ [ chatMessage ] } , scrollToBottomPort "div.messages" )
问题是 scrollToBottom
在 更新 model
之前被调用 。所以没什么大不了的,我将其转换为 Task
。但是,尽管 model
现在首先更新,但 view
还没有更新。所以我最终滚动到底部的第二个项目!
这可能会引出一个我在 Elm 中很好奇的更普遍的问题,你如何 运行 在视图因模型更改而更新后 Cmd
?
您可以使用端口滚动到列表底部。
在这种情况下,您需要设置一个 javascript 以在滚动之前等待 1 个 AnimationFrame。确保您的列表已呈现。
一个更简单的方法是使用 Elm 的 Dom.Scroll 库。
并使用 toBottom
函数。
如果您像这样在代码中包含它:
case msg of
Add ->
( model ++ [ newItem <| List.length model ]
, Task.attempt (always NoOp) <| Scroll.toBottom "idOfContainer"
)
NoOp ->
model ! []
应该可以。
我做了一个工作示例 here in runelm.io
Dom.Scroll 绝对是可行的方法,而且易于实施。
- 将要滚动的封闭 HTML 元素设置为具有不同的
ID。
- 确保所述元素的样式为 overflow-y: scroll 或
溢出-x:滚动。
- 从实际的任何消息发送命令
导致该元素为 displayed/opened(消息
opens/displays 元素,而您发出的命令将执行
滚动)。请注意,您使用命令是因为更改 DOM 在技术上是一种副作用。
查看说明滚动到底部的文档:
toBottom : Id -> Task Error ()
,可以看到需要是一个Task,所以可以wrap成Task.attempt
。例如:
Task.attempt (\_ -> NoOp) (Dom.Scroll.toBottom Id)
然后您将需要一个将 Result Error () 转换为 Msg 的函数,但是由于滚动不太可能失败或者如果失败也几乎没有缺点,您可以设置一个虚拟函数,例如 (\_ -> NoOp)
作为一个快速破解。
自版本 0.19 Dom
已弃用,您可以使用 Html.Attribute.property
函数设置滚动位置。
例子
import Html exposing (Html, text)
import Html.Attributes exposing (class, property)
import Json.Encode as Encode
view : Model -> Html Msg
view model =
div [ class "flow-editor"
, property "scrollLeft" (Encode.float model.scrollLeft)
, property "scrollTop" (Encode.float model.scrollTop)
]
[ text "placeholder" ]
从 Elm 0.19 开始,使用函数 Browser.Dom.getViewportOf
and Browser.Dom.setViewportOf
每次添加新元素时您都可以转到容器底部。
jumpToBottom : String -> Cmd Msg
jumpToBottom id =
Dom.getViewportOf id
|> Task.andThen (\info -> Dom.setViewportOf id 0 info.scene.height)
|> Task.attempt (\_ -> NoOp)
我将 <div>
s 添加到包装器 <div>
并且我需要能够滚动到每次添加的最后一个。我如何在 Elm 中执行此操作?
<div class="messages" style="height: 7em; overflow: scroll">
<div>Anonymous: Hello</div>
<div>John: Hi</div>
</div>
直觉上,我似乎可以调用 运行 的 JavaScript 代码 element.scrollTop = element.scrollHeight
:
AddChatMessage chatMessage ->
( { model | chatMessages = model.chatMessages ++ [ chatMessage ] } , scrollToBottomPort "div.messages" )
问题是 scrollToBottom
在 更新 model
之前被调用 。所以没什么大不了的,我将其转换为 Task
。但是,尽管 model
现在首先更新,但 view
还没有更新。所以我最终滚动到底部的第二个项目!
这可能会引出一个我在 Elm 中很好奇的更普遍的问题,你如何 运行 在视图因模型更改而更新后 Cmd
?
您可以使用端口滚动到列表底部。
在这种情况下,您需要设置一个 javascript 以在滚动之前等待 1 个 AnimationFrame。确保您的列表已呈现。
一个更简单的方法是使用 Elm 的 Dom.Scroll 库。
并使用 toBottom
函数。
如果您像这样在代码中包含它:
case msg of
Add ->
( model ++ [ newItem <| List.length model ]
, Task.attempt (always NoOp) <| Scroll.toBottom "idOfContainer"
)
NoOp ->
model ! []
应该可以。 我做了一个工作示例 here in runelm.io
Dom.Scroll 绝对是可行的方法,而且易于实施。
- 将要滚动的封闭 HTML 元素设置为具有不同的 ID。
- 确保所述元素的样式为 overflow-y: scroll 或 溢出-x:滚动。
- 从实际的任何消息发送命令 导致该元素为 displayed/opened(消息 opens/displays 元素,而您发出的命令将执行 滚动)。请注意,您使用命令是因为更改 DOM 在技术上是一种副作用。
查看说明滚动到底部的文档:
toBottom : Id -> Task Error ()
,可以看到需要是一个Task,所以可以wrap成Task.attempt
。例如:
Task.attempt (\_ -> NoOp) (Dom.Scroll.toBottom Id)
然后您将需要一个将 Result Error () 转换为 Msg 的函数,但是由于滚动不太可能失败或者如果失败也几乎没有缺点,您可以设置一个虚拟函数,例如 (\_ -> NoOp)
作为一个快速破解。
自版本 0.19 Dom
已弃用,您可以使用 Html.Attribute.property
函数设置滚动位置。
例子
import Html exposing (Html, text)
import Html.Attributes exposing (class, property)
import Json.Encode as Encode
view : Model -> Html Msg
view model =
div [ class "flow-editor"
, property "scrollLeft" (Encode.float model.scrollLeft)
, property "scrollTop" (Encode.float model.scrollTop)
]
[ text "placeholder" ]
从 Elm 0.19 开始,使用函数 Browser.Dom.getViewportOf
and Browser.Dom.setViewportOf
每次添加新元素时您都可以转到容器底部。
jumpToBottom : String -> Cmd Msg
jumpToBottom id =
Dom.getViewportOf id
|> Task.andThen (\info -> Dom.setViewportOf id 0 info.scene.height)
|> Task.attempt (\_ -> NoOp)