簡體   English   中英

如何在Elm中實現無限滾動?

[英]How to implement infinite scroll in Elm?

我嘗試為我的應用程序實現無限,並決定以下列方式執行此操作。 這里從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); }); })(); 

我認為它做了我需要的,但我不是百分百肯定。

我不明白的部分是如何在Elm代碼中處理這個問題。 我目前的方法(不起作用)如下。 我提供它只是為了讓我的意圖更清楚我想要實現的目標。

-- SUBSCRIPTIONS
port scroll : (Bool -> msg) -> Sub msg

subscriptions : Model -> Sub Msg 
subscriptions model = 
  scroll Scroll

完整的實施

這是一個沒有端口的工作實現: https//ellie-app.com/5R4Fw95QLQfa1

滾動到列表末尾時,它會加載更多列表項。

性能考慮因素

在此實現中,我們的事件解碼器獲取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
        }

為了使用方法實現無限滾動,我選擇了你需要的東西。 我將對正在發生的事情,主要組件是什么以及如何將它們組合在一起然后深入研究一些代碼進行高級概述。

抽象地說我需要遵循以下內容:

  • 我需要以某種方式對瀏覽器說我對scroll事件感興趣
  • 發生此事件時,我需要觸發一些代碼。

我如何說我對scroll事件感興趣的瀏覽器?

因為當前在Elm中滾動事件的實現要么不存在要么難以使用我決定使用jQuery來處理這些事件。

在這里,您可以看到我在index.html使用的所有代碼。 它沒有什么必要的東西:

  1. 它加載Elm應用程序並將其附加到頁面上的某些DOM元素

  2. 將回調綁定到每次發生此事件時將觸發的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); 

我想提請你注意這句話:

myApp.ports.scroll.send(isBottom);

以下是我將一些數據發送到Elm世界的方法。

myApp只是變量的名稱,它包含對Elm應用程序的引用,這里沒什么特別的。

ports只是您必須使用的關鍵字才能實現此類事情。

scroll這是將在Elm一側調用的函數名稱。 它由你定義(稍后我會告訴你如何做到這一點)

send是強制性的部分。 這是您向Elm app發送數據的方式。

現在,我需要做的就是以某種方式在Elm方面收到這些數據。

再次,高級概述。 現在數據正在向我的Elm應用程序前進,我需要做的就是訂閱此事件(我們沒有在Elm中回調,我們有訂閱:))

我是按照以下步驟完成的。 我用以下內容創建了名為Ports模塊:

port module Ports exposing (..)

port scroll : (Bool -> msg) -> Sub msg

如果您希望能夠從Elm的世界之外檢索數據,則必須在module關鍵字之前使用port關鍵字。

接下來,我在App.elm導入此模塊,這實際上是一些根級模塊(主協調節點)。 我只需要添加這一行:

import Ports exposing (..)

接下來,我需要在我的App.elm定義subscriptions ,如下所示:

subscriptions : Model -> Sub Msg 
subscriptions model = 
  scroll Scroll

基本上我訂閱了特定的事件,當這個事件發生時,將調度特定的Msg

我需要很少的其他東西來使整個事情有效:

  • 我需要將Scroll消息包含到我的Msg數據類型中

  • update功能中處理這種情況

    輸入Msg = NoOp | 滾動布爾

正如您所看到的,我在值構造函數Scroll指出我期望布爾值

當然還有update功能。 例如,根據pos true還是false,我會觸發一些代碼來加載更多的文章。

update msg model = 
  case msg of 
    NoOp -> 
      model ! []

    Scroll pos -> 
      -- do something with it 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM