2016-12-09 32 views
6

Tôi thêm <div> s vào trình bao bọc <div> và tôi cần có thể cuộn đến phần cuối cùng được thêm vào mỗi lần. Làm thế nào để làm điều này trong Elm?Cách tự động cuộn xuống dưới cùng của div trong Elm

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

trực giác, nó có vẻ như tôi có thể gọi một port chạy mã JavaScript element.scrollTop = element.scrollHeight:

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

Vấn đề là scrollToBottom được gọi trước các model được cập nhật. Vì vậy, không có vấn đề lớn, tôi chuyển đổi nó thành một Task. Nhưng vẫn còn, mặc dù các model được cập nhật đầu tiên ngay bây giờ, các view không được cập nhật được nêu ra. Vì vậy, tôi cuối cùng di chuyển đến mục thứ 2 từ phía dưới!

Điều này có thể dẫn đến một câu hỏi chung chung tôi tò mò về Elm, làm thế nào để bạn chạy một Cmd sau khi xem được cập nhật do sự thay đổi trong mô hình?

+0

Bạn có thể xem ứng dụng chính thức của TodoMVC elm. Tôi nghĩ rằng nó chỉ làm điều đó. (Trên thiết bị di động ngay bây giờ, nếu không sẽ có liên kết được chia sẻ). – wintvelt

+0

@wintvelt, Đây là ứng dụng TodoMVC Elm: https://github.com/evancz/elm-todomvc/blob/master/Todo.elm. Tôi không thấy bất cứ điều gì trong đó về di chuyển, chỉ có một cuộc gọi 'Dom.focus'. 'index.html' và tệp CSS cũng không cung cấp bất kỳ chỉ báo nào về tự động cuộn. –

+0

Bạn nói đúng. Nó không có trong ứng dụng todomvc. Lỗi của tôi. Sẽ thêm một câu trả lời dưới đây. – wintvelt

Trả lời

5

Bạn có thể sử dụng cổng để cuộn xuống cuối danh sách.
Trong trường hợp đó, bạn cần đặt javascript để chờ 1 AnimationFrame trước khi thực hiện cuộn. Để đảm bảo danh sách của bạn được hiển thị.

Cách dễ dàng hơn để thực hiện việc này là sử dụng thư viện Dom.Scroll của Elm.
Và sử dụng chức năng toBottom.

Nếu bạn bao gồm rằng trong mã của bạn như thế này:

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

    NoOp -> 
     model ! [] 

Nó sẽ làm việc. Tôi đã tạo một ví dụ làm việc here in runelm.io

+0

Không biết về 'Dom.Scroll'! Cảm ơn. Trước đây tôi đã thử 'Task.perform' với lệnh gọi JavaScript' port' và JavaScript không nhìn thấy mục cuối cùng. Tôi tự hỏi nếu đó là bởi vì 'Dom.Scroll' hoạt động trên dom ảo và vì vậy nó nhìn thấy mục cuối cùng và có thể di chuyển xuống nó. Mặc dù JavaScript không thể thấy được bản cập nhật thực sự được cập nhật ... –

1

Dom.Scroll chắc chắn là cách để thực hiện và dễ thực hiện.

  1. Đặt phần tử HTML kèm theo mà bạn muốn cuộn để có một mã số riêng biệt .
  2. Đảm bảo yếu tố được nói có kiểu dáng tràn-y: cuộn hoặc tràn-x: cuộn.
  3. Gửi lệnh từ bất kỳ thông báo nào thực sự khiến phần tử đó được hiển thị/mở (thư mở/hiển thị phần tử trong khi lệnh bạn kích hoạt sẽ di chuyển ). Lưu ý rằng bạn sử dụng lệnh vì việc thay đổi DOM về mặt kỹ thuật là một tác dụng phụ.

Nhìn vào tài liệu cho tiếng nói di chuyển đến phía dưới: toBottom : Id -> Task Error(), bạn có thể thấy rằng nó cần phải được một nhiệm vụ, vì vậy bạn có thể quấn vào Task.attempt. Ví dụ: Task.attempt (\_ -> NoOp) (Dom.Scroll.toBottom Id)

Sau đó, bạn sẽ cần một hàm để chuyển đổi Lỗi kết quả() thành Msg, nhưng vì việc di chuyển có thể không thành công hoặc có ít nhược điểm nếu có, bạn có thể thiết lập chức năng giả Thay vào đó, (\_ -> NoOp) là một bản hack nhanh.

Các vấn đề liên quan