Rails使用Turbo事件,如何将页面滚动到底部?


聊天应用里面的,最新消息在最下面显示的时候,如果将当前窗口移动到scroll到底部最新消息的位置呢?

使用javascript可以通过

  <%= turbo_stream_from @conversation %>
        <div class="chat-room" id="chat-room-container">
          <%= turbo_frame_tag "conversation" do %>
      .................
          <% end %>
          <div class="convo-comments-container-<%= @conversation.id %>" id="conversation_comments">
            <%= render @conversation.conversation_comments %>
          </div>
        </div>
        <div class="chat-box">
          <%= turbo_frame_tag 'new_conversation_conversation_comment', src: new_conversation_conversation_comment_path(@conversation), target: "_top" %>
        </div>

  $('#conversation_comments').animate({scrollTop: 20000000}, "slow");

  const msgs = document.getElementById('conversation_comments');

  function getMessages() {
      // Prior to getting your messages.
      shouldScroll = msgs.scrollTop + msgs.clientHeight === msgs.scrollHeight;

      // After getting your messages.
      if (!shouldScroll) {
          scrollToBottom();
      }
  }

  function scrollToBottom() {
      msgs.scrollTop = msgs.scrollHeight;
  }

  scrollToBottom();

 // setInterval(getMessages, 2000);

  document.addEventListener("turbo:render", function (){
      getMessages();
  });
</script>

但是现在页面并未刷新,上面的js并不能执行。

The Stimulus docs are fairly good on this: Stimulus Reference: Lifecycle Callbacks 43

I found the solution. Stimulus example: smart scroll · GitHub 217


<div data-controller="smart-scroll"
data-action="smart-scroll:added->smart-scroll#handleAdded 
 resize->smart-scroll#handleAdded 
 scroll->smart-scroll#handleScroll">
<div data-controller="smart-scroll-item">
 aya: an an
</div>
<div data-controller="smart-scroll-item">
 hatate: ni hao
</div>
<!-- add more smart-scroll-item dynamically... -->
</div>

import { Controller } from 'stimulus'
import Rails from 'rails-ujs'

const observer = new ResizeObserver(entries => {
for (let entry of entries) {
Rails.fire(entry.target, 'resize')
}
})

export default class extends Controller {
connect() {
observer.observe(this.element)
this.shouldScroll = true
this.scrollToBottom()
}

disconnect() {
observer.unobserve(this.element)
}

scrollToBottom() {
const { scrollHeight, clientHeight, offsetHeight } = this.element
if (scrollHeight >= clientHeight) {
this.element.scrollTop = scrollHeight - clientHeight
}
}

handleAdded() {
const { scrollHeight, clientHeight } = this.element
if (clientHeight >= scrollHeight) {
this.shouldScroll = true
}

if (this.shouldScroll) {
this.scrollToBottom()
}
}

handleScroll() {
const { scrollTop, scrollHeight, clientHeight, offsetHeight } = this.element
if (clientHeight >= scrollHeight) {
this.shouldScroll = true
} else {
this.shouldScroll =
Math.abs((scrollTop + offsetHeight) - scrollHeight) < 1
}
}
}

 smart_scroll_item_controller.js 

import { Controller } from 'stimulus'
import { getParentController } from 'stimulus_utils'
import Rails from 'rails-ujs'

export default class extends Controller {
connect() {
const parent = getParentController(this, 'smart-scroll')
Rails.fire(parent.element, 'smart-scroll:added')
}

}



 stimulus_utils.js 

export function getParentController(controller, identifier) {
const application = controller.application
let element = controller.element
do {
let foundController =
application.getControllerForElementAndIdentifier(element, identifier)
if (foundController) {
return foundController
}
} while (element = element.parentElement)
}


阅读量: 944
发布于:
修改于: