自动滚动聊天界面

42

我有这段代码,用于加载聊天室

function getMessages(letter) {
  var div = $('#messages');
  $.get('msg_show.php', function (data) {
    div.html(data);
  });
}

setInterval(getMessages, 100);

我需要添加什么才能在页面加载时自动滚动#messages div,以及每次新聊天发布时都自动滚动?
这个方法无效:
function getMessages(letter) {
  var div = $('#messages');
  $.get('msg_show.php', function (data) {
    div.html(data);
    $('#messages').scrollTop($('#messages')[0].scrollHeight);
  });
}

setInterval(getMessages, 100);

3
如果你的元素ID是messages,那么可能应该是document.getElementById('messages')(注意缺少#)。 - UweB
1
抱歉,实际上我没有带 #。 - Adam Výborný
16个回答

67

首先,让我们回顾一些有关滚动的有用概念:

何时应该滚动?

  • 用户第一次加载消息时。
  • 新消息已到达并且您在滚动底部(当用户向上滚动以阅读以前的消息时,不要强制滚动)。

编程实现:

if (firstTime) {
  container.scrollTop = container.scrollHeight;
  firstTime = false;
} else if (container.scrollTop + container.clientHeight === container.scrollHeight) {
  container.scrollTop = container.scrollHeight;
}

全聊天模拟器(使用JavaScript):

https://jsfiddle.net/apvtL9xa/

const messages = document.getElementById('messages');

function appendMessage() {
 const message = document.getElementsByClassName('message')[0];
  const newMessage = message.cloneNode(true);
  messages.appendChild(newMessage);
}

function getMessages() {
 // Prior to getting your messages.
  shouldScroll = messages.scrollTop + messages.clientHeight === messages.scrollHeight;
  /*
   * Get your messages, we'll just simulate it by appending a new one syncronously.
   */
  appendMessage();
  // After getting your messages.
  if (!shouldScroll) {
    scrollToBottom();
  }
}

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

scrollToBottom();

setInterval(getMessages, 100);
#messages {
  height: 200px;
  overflow-y: auto;
}
<div id="messages">
  <div class="message">
    Hello world
  </div>
</div>


10
2019年1月16日,现在页面一直自动向下滚动。 - Nerdi.org
2
如果您的容器高度不是整数,那么您可能需要使用 container.scrollTop + container.clientHeight >= container.scrollHeight 作为测试。 - btmorex
我现在无法向上滚动。 - marc-stupid
对我来说,显式指定消息容器的 height 是有效的。 - murtuzaali_surti

15
很难在不知道HTML代码的情况下判断,但我猜测您的div没有设置高度和/或不允许溢出(例如通过CSS height: 200px; overflow: auto)。
我在jsfiddle上制作了一个可工作的示例:http://jsfiddle.net/hu4zqq4x/ 我在一个div中创建了一些虚拟HTML标记,这个div a) 溢出并且b) 设置了高度。 通过调用函数进行滚动。
function getMessages(letter) {
    var div = $("#messages");
    div.scrollTop(div.prop('scrollHeight'));
}

在这种情况下,代码将在“documentReady”事件触发时执行一次。

prop('scrollHeight') 将访问匹配元素集中第一个元素的属性值。


9
在 JQuery 中添加后,只需添加这一行代码
<script>
    $("#messages").animate({ scrollTop: 20000000 }, "slow");
</script>

2
如果仅仅使用scrollheight,当用户想查看之前的消息时会出现问题。因此,您需要做一些处理,只有在新消息到来时才能滚动。请使用最新版本的jQuery。 1.在消息加载前检查高度。 2.再次检查新的高度。 3.如果高度不同,那么它才会滚动,否则就不会滚动。 4.在if条件中,您可以放置任何铃声或其他功能,这将在新消息到来时播放。谢谢
var oldscrollHeight = $("#messages").prop("scrollHeight");
$.get('msg_show.php', function(data) {
    div.html(data);
    var newscrollHeight = $("#messages").prop("scrollHeight"); //Scroll height after the request
    if (newscrollHeight > oldscrollHeight) {
        $("#messages").animate({
            scrollTop: newscrollHeight
        }, 'normal'); //Autoscroll to bottom of div
    }

终于有一个解决方案对我真正起作用了,谢谢 :) - Rishabh

2

要滚动到消息框顶部的特定元素,请查看以下演示:

https://jsfiddle.net/6smajv0t/

function scrollToBottom(){
 const messages = document.getElementById('messages');
 const messagesid = document.getElementById('messagesid');  
 messages.scrollTop = messagesid.offsetTop - 10;
}

scrollToBottom();
setInterval(scrollToBottom, 1000);
#messages {
  height: 200px;
  overflow-y: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="messages">
  <div class="message">
    Hello world1
  </div>
  <div class="message">
    Hello world2
  </div>
  <div class="message">
    Hello world3
  </div>
  <div class="message">
    Hello world4
  </div>
  <div class="message">
    Hello world5
  </div>
  <div class="message">
    Hello world7
  </div>
  <div class="message">
    Hello world8
  </div>
  <div class="message">
    Hello world9
  </div>
  <div class="message" >
    Hello world10
  </div>
  <div class="message">
    Hello world11
  </div>
  <div class="message">
    Hello world12
  </div>
  <div class="message">
    Hello world13
  </div>
  <div class="message">
    Hello world14
  </div>
  <div class="message">
    Hello world15
  </div>
  <div class="message" id="messagesid">
    Hello world16 here
  </div>
  <div class="message">
    Hello world17
  </div>
  <div class="message">
    Hello world18
  </div>
  <div class="message">
    Hello world19
  </div>
  <div class="message">
    Hello world20
  </div>
  <div class="message">
    Hello world21
  </div>
  <div class="message">
    Hello world22
  </div>
  <div class="message">
    Hello world23
  </div>
  <div class="message">
    Hello world24
  </div>
  <div class="message">
    Hello world25
  </div>
  <div class="message">
    Hello world26
  </div>
  <div class="message">
    Hello world27
  </div>
  <div class="message">
    Hello world28
  </div>
  <div class="message">
    Hello world29
  </div>
  <div class="message">
    Hello world30
  </div>
</div>


1

简单解决方案:

1 - 将其放置在您的消息底部(内部)

<a href="#" class="d-none" id="focus-bottom"></a>

2-当收到新消息时:
function getMessages (letter) {
  var div = $('#messages');
  $.get('msg_show.php', function(data){
    div.html(data);
    $('#focus-bottom').focus();
    $('#focus-box-message').focus(); / * FOCUS YOUR TEXTAREA * /
  });
}

setInterval(getMessages, 100);

1
我在实验中发现了这个非常简单的方法:将 scrollTo 设置为 div 的高度。
var myDiv = document.getElementById("myDiv");
window.scrollTo(0, myDiv.innerHeight);

1
你需要做的是将其分为两个div。一个设置overflow为scroll,另一个用于容纳文本,以便获取其外部尺寸。
<div id="chatdiv">
    <div id="textdiv"/>
</div>

textdiv.html("");
$.each(chatMessages, function (i, e) {
    textdiv.append("<span>" + e + "</span><br/>");
});
chatdiv.scrollTop(textdiv.outerHeight());

您可以在此处查看jsfiddle:http://jsfiddle.net/xj5c3jcn/1/

显然,您不希望每次重建整个文本div,因此请将其视为参考示例。


0

支持新消息和自动向下滚动设置类似于Twitch聊天

function Chat() {
    const [messages, setMessages] = useState<string[]>([])
    const container = useRef<HTMLDivElement>(null)

    const autoScroll = () => {
        const { offsetHeight, scrollHeight, scrollTop } = container.current as HTMLDivElement
        if (scrollHeight <= scrollTop + offsetHeight + 100) {
            container.current?.scrollTo(0, scrollHeight)
        }
    }

    useEffect(() => {
        autoScroll()
    }, [messages])

    return (
        <div ref={container}>
            // messages
        </div>
    )
}

0
    var l = document.getElementsByClassName("chatMessages").length;
    document.getElementsByClassName("chatMessages")[l-1].scrollIntoView();

这应该可以工作


如果您的聊天框中包含的聊天消息不在视图中,那么这将滚动整个页面,并将聊天框带入视图。 这不是您想要的结果。 - Bibek Shrestha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接