2016-12-09 2 views
6

Ich füge <div> s zu einem Wrapper <div> und ich muss in der Lage sein, bis zum letzten jedes Mal hinzugefügt scrollen. Wie mache ich das in Elm?Wie automatisches Scrollen bis zum Ende eines Div in Elm

<div class="messages" style="height: 7em; overflow: scroll"> 
    <div>Anonymous: Hello</div> 
    <div>John: Hi</div> 
</div> 

Intuitiv scheint es, wie ich ein port nennen könnte, die den JavaScript-Code läuft element.scrollTop = element.scrollHeight:

AddChatMessage chatMessage -> 
    ({ model | chatMessages = model.chatMessages ++ [ chatMessage ] } , scrollToBottomPort "div.messages") 

Das Problem wird scrollToBottomaufgerufen wird, bevor die model aktualisiert wird. Also keine große Sache, ich konvertiere das in eine Task. Aber auch wenn die model jetzt zuerst aktualisiert wird, wird die view noch nicht aktualisiert. Also scrolle ich zum zweiten Punkt von unten!

Dies führt vielleicht zu einer allgemeineren Frage, auf die ich mich in Elm freue, wie läuft ein Cmd, nachdem die Ansicht aufgrund einer Änderung im Modell aktualisiert wurde?

+0

Sie können sich die offizielle TodoMVC Ulme App ansehen. Ich denke, dass es genau das tut. (Auf Handy jetzt, sonst hätte Link geteilt). – wintvelt

+0

@wintvelt, Hier ist die TodoMVC Elm App: https://github.com/evancz/elm-todomvc/blob/master/Todo.elm. Ich habe dort nichts über Scrollen gesehen, nur einen 'Dom.focus' Anruf. 'index.html' und die CSS-Datei lieferte auch keinen Hinweis auf automatisches Scrollen. –

+0

Sie haben Recht. Es ist nicht in der Todomvc App. Mein Fehler. Wird eine Antwort unten hinzufügen. – wintvelt

Antwort

5

Sie können einen Port verwenden, um zum Ende einer Liste zu blättern.
In diesem Fall müssen Sie ein JavaScript einstellen, um auf 1 AnimationFrame zu warten, bevor Sie den Bildlauf durchführen. Um sicherzustellen, dass Ihre Liste gerendert wird.

Ein einfacher Weg, dies zu tun ist, Elms Dom.Scroll Bibliothek zu verwenden.
Und verwenden Sie die toBottom Funktion.

Wenn Sie beinhalten, dass in Ihrem Code wie folgt aus:

case msg of 
    Add -> 
     (model ++ [ newItem <| List.length model ] 
     , Task.attempt (always NoOp) <| Scroll.toBottom "idOfContainer" 
     ) 

    NoOp -> 
     model ! [] 

Es sollte funktionieren. Ich habe ein funktionierendes Beispiel gemacht here in runelm.io

+0

Ich habe nichts von 'Dom.Scroll' gehört! Vielen Dank. Ich hatte vorher 'Task.perform' mit einem JavaScript' port'-Aufruf versucht und JavaScript konnte das letzte Element nicht sehen. Ich frage mich, ob es daran liegt, dass 'Dom.Scroll' auf dem virtuellen Dom funktioniert und so den letzten Gegenstand sieht und runterscrollen kann. Während JavaScript die reale Domäne noch nicht aktualisiert werden kann, ... –

1

Dom.Scroll ist definitiv der Weg zu gehen und ist einfach zu implementieren.

  1. Legen Sie das einschließende HTML-Element fest, das durchsucht werden soll, um eine eindeutige ID zu haben.
  2. Stellen Sie sicher, dass das Element das Styling von overflow-y hat: scroll oder overflow-x: scroll.
  3. Senden Sie einen Befehl von welcher Nachricht auch immer bewirkt, dass dieses Element angezeigt/geöffnet wird (die Nachricht öffnet/zeigt das Element, während der Befehl, den Sie auslösen, den scroll). Beachten Sie, dass Sie einen Befehl verwenden, da das Ändern des DOM technisch ein Nebeneffekt ist.

bei der Dokumentation der Suche nach etwa nach unten scrollen: toBottom : Id -> Task Error(), können Sie sehen, dass es braucht, um eine Aufgabe zu sein, so dass Sie in Task.attempt wickeln können. Zum Beispiel: Task.attempt (\_ -> NoOp) (Dom.Scroll.toBottom Id)

Sie erhalten dann eine Funktion benötigen ein Ergebnis Error() in eine Nachricht zu konvertieren, aber da Scrollen entweder unwahrscheinlich oder wenig Nachteil hat versagen, wenn es der Fall ist, können Sie eine Dummy-Funktion wie eingesetzten (\_ -> NoOp) als ein schneller Hack statt.

Verwandte Themen