我尝试为我的应用程序实现无限,并决定以下列方式执行此操作.这里从中提取的代码index.html将Elm app绑定到特定节点,并定义了一些将在scroll事件上触发的代码:
(function() {
var loadMore = function () {
return $(window).scrollTop() === $(document).height() - $(window).height()
};
var node = document.getElementById('main');
var myApp = Elm.Main.embed(node);
$(window).bind('scroll', function () {
var isBottom = loadMore();
myApp.ports.scroll.send(isBottom);
});
})();Run Code Online (Sandbox Code Playgroud)
我认为它做了我需要的,但我不是百分百肯定.
我不明白的部分是如何在Elm代码中处理这个问题.我目前的方法(不起作用)如下.我提供它只是为了让我的意图更清楚我想要实现的目标.
-- SUBSCRIPTIONS
port scroll : (Bool -> msg) -> Sub msg
subscriptions : Model -> Sub Msg
subscriptions model =
scroll Scroll
Run Code Online (Sandbox Code Playgroud)
这是一个简短,自包含,可编译的完整实现示例,没有端口,您只需复制并粘贴到http://elm-lang.org/try即可使用.滚动到列表末尾时,它会加载更多列表项.
在此实现中,我们的事件解码器正在获取offsetHeight有关容器高度的信息.这会导致不断的回流并可能影响程序的性能.更好的选择是事先知道scroll元素的高度,或者在找到height值后立即删除事件监听器.
module Main exposing (main)
import Browser
import Html
import Html exposing (Html, Attribute, ul, li, text, button, div)
import Html.Attributes exposing (..)
import Html.Events exposing (onInput, onClick, on)
import Json.Decode
import List
import String
type alias Model = List String
initialModel =
[ "Pamplemousse"
, "Ananas"
, "Jus d'orange"
, "Boeuf"
, "Soupe du jour"
, "Camembert"
, "Jacques Cousteau"
, "Baguette"
]
-- UPDATE
type Msg
= LoadMore
| ScrollEvent ScrollInfo
type alias ScrollInfo =
{ scrollHeight : Float
, scrollTop : Float
, offsetHeight : Float
}
update msg model =
case msg of
LoadMore ->
List.concat [ model, initialModel ]
ScrollEvent { scrollHeight, scrollTop, offsetHeight } ->
if (scrollHeight - scrollTop) <= offsetHeight then
List.concat [ model, initialModel ]
else
model
-- VIEW
view content =
div [ onScroll ScrollEvent ]
[ ul
[ class "grocery-list"
, style "height" "300px"
, style "display" "block"
, style "overflow" "scroll"
, onScroll ScrollEvent
]
(List.map listItem content)
, button [ onClick LoadMore ] [ text "load more" ]
]
listItem itemText =
li
[ style "height" "50px"
, style "display" "block"
]
[ text itemText ]
onScroll msg =
on "scroll" (Json.Decode.map msg scrollInfoDecoder)
scrollInfoDecoder =
Json.Decode.map3 ScrollInfo
(Json.Decode.at [ "target", "scrollHeight" ] Json.Decode.float)
(Json.Decode.at [ "target", "scrollTop" ] Json.Decode.float)
(Json.Decode.at [ "target", "offsetHeight" ] Json.Decode.float)
main : Program () Model Msg
main =
Browser.sandbox
{ init = initialModel
, view = view
, update = update
}
Run Code Online (Sandbox Code Playgroud)
为了使用我选择的方法实现无限滚动,您需要做一些事情。我将简要概述正在发生的事情、主要组件是什么以及这一切如何组合在一起,然后深入研究一些代码。
抽象地说我需要以下东西:
scroll事件感兴趣我如何向浏览器表明我对scroll事件感兴趣?
因为 Elm 中滚动事件的当前实现要么不存在,要么很难使用,所以我决定使用jQuery来处理这些事件。
您可以在这里看到我使用的所有代码index.html。它做了一些重要的事情:
它加载 Elm 应用程序并将其附加到页面上的某个 DOM 元素
将回调绑定到scroll每次事件发生时都会触发的事件
(function($) {
var loadMore = function () {
return $(window).scrollTop() === $(document).height() - $(window).height()
};
var node = document.getElementById('main');
var myApp = Elm.Main.embed(node);
$(window).bind('scroll', function () {
var isBottom = loadMore();
myApp.ports.scroll.send(isBottom);
});
})(jQuery);
Run Code Online (Sandbox Code Playgroud)我想提请您注意这一行:
myApp.ports.scroll.send(isBottom);
Run Code Online (Sandbox Code Playgroud)
这是我将一些数据发送到 Elm world 的方法。
myApp只是保存 Elm 应用程序引用的变量名称,这里没什么花哨的。
ports只是为了实现此类事情而必须使用的关键字。
scroll这是将在 Elm 端调用的函数名称。它由您定义(稍后我将展示如何做到这一点)
send是强制性部分。这是将数据发送到 Elm 应用程序的方式。
现在我需要做的就是以某种方式在 Elm 端接收这些数据。
再次,高层次概述。现在数据正在发送到我的 Elm 应用程序,我所需要做的就是订阅此事件(我们在 Elm 中没有回调,我们有订阅:))
我按照以下步骤完成了此操作。我创建了名为Ports以下内容的模块:
port module Ports exposing (..)
port scroll : (Bool -> msg) -> Sub msg
Run Code Online (Sandbox Code Playgroud)
portmodule如果您希望能够从 Elm 世界之外检索数据,则关键字之前的关键字是必需的。
接下来,我将此模块导入到 my 中App.elm,这本质上是一些根级模块(主要协调节点)。我只需要添加这一行:
import Ports exposing (..)
Run Code Online (Sandbox Code Playgroud)
接下来,我需要subscriptions像App.elm这样定义:
subscriptions : Model -> Sub Msg
subscriptions model =
scroll Scroll
Run Code Online (Sandbox Code Playgroud)
本质上,我订阅特定事件,当该事件发生时,特定事件Msg将被调度。
我需要一些其他东西才能使整个事情正常进行:
我需要将Scroll消息包含到我的Msg数据类型中
update在函数中处理这种情况
类型消息 = NoOp | 滚动布尔值
正如你所看到的,我在值构造函数中指出Scroll我期待布尔值
当然还有update功能。pos例如,根据true 或 false,我触发一些代码来加载更多文章。
update msg model =
case msg of
NoOp ->
model ! []
Scroll pos ->
-- do something with it
Run Code Online (Sandbox Code Playgroud)