我有一个div,只有300像素大,我希望它在页面加载时滚动到内容的底部。这个div有动态添加的内容,需要一直向下滚动。现在如果用户决定向上滚动,我不希望它跳回底部,直到用户再次向下滚动
是否有可能有一个div,将保持滚动到底部,除非用户向上滚动,当用户滚动回底部时,它需要保持自己在底部,即使添加了新的动态内容。我该怎么做呢。
我有一个div,只有300像素大,我希望它在页面加载时滚动到内容的底部。这个div有动态添加的内容,需要一直向下滚动。现在如果用户决定向上滚动,我不希望它跳回底部,直到用户再次向下滚动
是否有可能有一个div,将保持滚动到底部,除非用户向上滚动,当用户滚动回底部时,它需要保持自己在底部,即使添加了新的动态内容。我该怎么做呢。
当前回答
这里有一个基于Ryan Hunt博客文章的解决方案。它取决于overflow-anchor CSS属性,该属性将滚动位置固定在滚动内容底部的元素上。
function addMessage() { const $message = document.createElement('div'); $message.className = 'message'; $message.innerText = `Random number = ${Math.ceil(Math.random() * 1000)}`; $messages.insertBefore($message, $anchor); // Trigger the scroll pinning when the scroller overflows if (!overflowing) { overflowing = isOverflowing($scroller); $scroller.scrollTop = $scroller.scrollHeight; } } function isOverflowing($el) { return $el.scrollHeight > $el.clientHeight; } const $scroller = document.querySelector('.scroller'); const $messages = document.querySelector('.messages'); const $anchor = document.querySelector('.anchor'); let overflowing = false; setInterval(addMessage, 1000); .scroller { overflow: auto; height: 90vh; max-height: 11em; background: #555; } .messages > * { overflow-anchor: none; } .anchor { overflow-anchor: auto; height: 1px; } .message { margin: .3em; padding: .5em; background: #eee; } <section class="scroller"> <div class="messages"> <div class="anchor"></div> </div> </section>
注意,overflow-anchor目前在Safari中不起作用。
其他回答
//Make sure message list is scrolled to the bottom
var container = $('#MessageWindowContent')[0];
var containerHeight = container.clientHeight;
var contentHeight = container.scrollHeight;
container.scrollTop = contentHeight - containerHeight;
以下是我基于dotnetCarpenter回答的版本。我的方法是一个纯jQuery和我命名的变量,使事情更清楚一点。发生的情况是,如果内容高度大于容器高度,我们向下滚动额外的距离以实现所需的结果。
工作在IE和chrome..
以下是你所需要的(我尽了最大的努力,一路上进行了大量的谷歌搜索):
<html>
<head>
<script>
// no jquery, or other craziness. just
// straight up vanilla javascript functions
// to scroll a div's content to the bottom
// if the user has not scrolled up. Includes
// a clickable "alert" for when "content" is
// changed.
// this should work for any kind of content
// be it images, or links, or plain text
// simply "append" the new element to the
// div, and this will handle the rest as
// proscribed.
let scrolled = false; // at bottom?
let scrolling = false; // scrolling in next msg?
let listener = false; // does element have content changed listener?
let contentChanged = false; // kind of obvious
let alerted = false; // less obvious
function innerHTMLChanged() {
// this is here in case we want to
// customize what goes on in here.
// for now, just:
contentChanged = true;
}
function scrollToBottom(id) {
if (!id) { id = "scrollable_element"; }
let DEBUG = 0; // change to 1 and open console
let dstr = "";
let e = document.getElementById(id);
if (e) {
if (!listener) {
dstr += "content changed listener not active\n";
e.addEventListener("DOMSubtreeModified", innerHTMLChanged);
listener = true;
} else {
dstr += "content changed listener active\n";
}
let height = (e.scrollHeight - e.offsetHeight); // this isn't perfect
let offset = (e.offsetHeight - e.clientHeight); // and does this fix it? seems to...
let scrollMax = height + offset;
dstr += "offsetHeight: " + e.offsetHeight + "\n";
dstr += "clientHeight: " + e.clientHeight + "\n";
dstr += "scrollHeight: " + e.scrollHeight + "\n";
dstr += "scrollTop: " + e.scrollTop + "\n";
dstr += "scrollMax: " + scrollMax + "\n";
dstr += "offset: " + offset + "\n";
dstr += "height: " + height + "\n";
dstr += "contentChanged: " + contentChanged + "\n";
if (!scrolled && !scrolling) {
dstr += "user has not scrolled\n";
if (e.scrollTop != scrollMax) {
dstr += "scroll not at bottom\n";
e.scroll({
top: scrollMax,
left: 0,
behavior: "auto"
})
e.scrollTop = scrollMax;
scrolling = true;
} else {
if (alerted) {
dstr += "alert exists\n";
} else {
dstr += "alert does not exist\n";
}
if (contentChanged) { contentChanged = false; }
}
} else {
dstr += "user scrolled away from bottom\n";
if (!scrolling) {
dstr += "not auto-scrolling\n";
if (e.scrollTop >= scrollMax) {
dstr += "scroll at bottom\n";
scrolled = false;
if (alerted) {
dstr += "alert exists\n";
let n = document.getElementById("alert");
n.remove();
alerted = false;
contentChanged = false;
scrolled = false;
}
} else {
dstr += "scroll not at bottom\n";
if (contentChanged) {
dstr += "content changed\n";
if (!alerted) {
dstr += "alert not displaying\n";
let n = document.createElement("div");
e.append(n);
n.id = "alert";
n.style.position = "absolute";
n.classList.add("normal-panel");
n.classList.add("clickable");
n.classList.add("blink");
n.innerHTML = "new content!";
let nposy = parseFloat(getComputedStyle(e).height) + 18;
let nposx = 18 + (parseFloat(getComputedStyle(e).width) / 2) - (parseFloat(getComputedStyle(n).width) / 2);
dstr += "nposx: " + nposx + "\n";
dstr += "nposy: " + nposy + "\n";
n.style.left = nposx;
n.style.top = nposy;
n.addEventListener("click", () => {
dstr += "clearing alert\n";
scrolled = false;
alerted = false;
contentChanged = false;
n.remove();
});
alerted = true;
} else {
dstr += "alert already displayed\n";
}
} else {
alerted = false;
}
}
} else {
dstr += "auto-scrolling\n";
if (e.scrollTop >= scrollMax) {
dstr += "done scrolling";
scrolling = false;
scrolled = false;
} else {
dstr += "still scrolling...\n";
}
}
}
}
if (DEBUG && dstr) console.log("stb:\n" + dstr);
setTimeout(() => { scrollToBottom(id); }, 50);
}
function scrollMessages(id) {
if (!id) { id = "scrollable_element"; }
let DEBUG = 1;
let dstr = "";
if (scrolled) {
dstr += "already scrolled";
} else {
dstr += "got scrolled";
scrolled = true;
}
dstr += "\n";
if (contentChanged && alerted) {
dstr += "content changed, and alerted\n";
let n = document.getElementById("alert");
if (n) {
dstr += "alert div exists\n";
let e = document.getElementById(id);
let nposy = parseFloat(getComputedStyle(e).height) + 18;
dstr += "nposy: " + nposy + "\n";
n.style.top = nposy;
} else {
dstr += "alert div does not exist!\n";
}
} else {
dstr += "content NOT changed, and not alerted";
}
if (DEBUG && dstr) console.log("sm: " + dstr);
}
setTimeout(() => { scrollToBottom("messages"); }, 1000);
/////////////////////
// HELPER FUNCTION
// simulates adding dynamic content to "chat" div
let count = 0;
function addContent() {
let e = document.getElementById("messages");
if (e) {
let br = document.createElement("br");
e.append("test " + count);
e.append(br);
count++;
}
}
</script>
<style>
button {
border-radius: 5px;
}
#container {
padding: 5px;
}
#messages {
background-color: blue;
border: 1px inset black;
border-radius: 3px;
color: white;
padding: 5px;
overflow-x: none;
overflow-y: auto;
max-height: 100px;
width: 100px;
margin-bottom: 5px;
text-align: left;
}
.bordered {
border: 1px solid black;
border-radius: 5px;
}
.inline-block {
display: inline-block;
}
.centered {
text-align: center;
}
.normal-panel {
background-color: #888888;
border: 1px solid black;
border-radius: 5px;
padding: 2px;
}
.clickable {
cursor: pointer;
}
</style>
</head>
<body>
<div id="container" class="bordered inline-block centered">
<div class="inline-block">My Chat</div>
<div id="messages" onscroll="scrollMessages('messages')">
test<br>
test<br>
test<br>
test<br>
test<br>
test<br>
test<br>
test<br>
test<br>
test<br>
</div>
<button onclick="addContent();">Add Content</button>
</div>
</body>
</html>
注意:你可能需要在scrollToBottom和scrollMessages中调整警报位置(nposx和nposy)来匹配你的需求…
还有一个链接到我自己的工作示例,托管在我的服务器上:https://night-stand.ca/jaretts_tests/chat_scroll.html
我不能让前两个答案工作,其他答案都对我没有帮助。所以我从Reddit r/forhire和Upwork上给了三个人30美元,得到了一些非常好的答案。这个答案可以帮你省下90美元。
Justin Hundley / The Site Bros的解决方案
HTML
<div id="chatscreen">
<div id="inner">
</div>
</div>
CSS
#chatscreen {
width: 300px;
overflow-y: scroll;
max-height:100px;
}
Javascript
$(function(){
var scrolled = false;
var lastScroll = 0;
var count = 0;
$("#chatscreen").on("scroll", function() {
var nextScroll = $(this).scrollTop();
if (nextScroll <= lastScroll) {
scrolled = true;
}
lastScroll = nextScroll;
console.log(nextScroll, $("#inner").height())
if ((nextScroll + 100) == $("#inner").height()) {
scrolled = false;
}
});
function updateScroll(){
if(!scrolled){
var element = document.getElementById("chatscreen");
var inner = document.getElementById("inner");
element.scrollTop = inner.scrollHeight;
}
}
// Now let's load our messages
function load_messages(){
$( "#inner" ).append( "Test" + count + "<br/>" );
count = count + 1;
updateScroll();
}
setInterval(load_messages,300);
});
预览网站兄弟的解决方案
投资组合
莱尔梅克斯/斯维亚托斯拉夫·丘马科夫的解决方案
HTML
<div id="chatscreen">
</div>
CSS
#chatscreen {
height: 300px;
border: 1px solid purple;
overflow: scroll;
}
Javascript
$(function(){
var isScrolledToBottom = false;
// Now let's load our messages
function load_messages(){
$( "#chatscreen" ).append( "<br>Test" );
updateScr();
}
var out = document.getElementById("chatscreen");
var c = 0;
$("#chatscreen").on('scroll', function(){
console.log(out.scrollHeight);
isScrolledToBottom = out.scrollHeight - out.clientHeight <= out.scrollTop + 10;
});
function updateScr() {
// allow 1px inaccuracy by adding 1
//console.log(out.scrollHeight - out.clientHeight, out.scrollTop + 1);
var newElement = document.createElement("div");
newElement.innerHTML = c++;
out.appendChild(newElement);
console.log(isScrolledToBottom);
// scroll to bottom if isScrolledToBotto
if(isScrolledToBottom) {out.scrollTop = out.scrollHeight - out.clientHeight; }
}
var add = setInterval(updateScr, 1000);
setInterval(load_messages,300); // change to 300 to show the latest message you sent after pressing enter // comment this line and it works, uncomment and it fails
// leaving it on 1000 shows the second to last message
setInterval(updateScroll,30);
});
预览Sviatoslav的解决方案
投资组合
伊戈尔·鲁西诺夫的解决方案
HTML
<div id="chatscreen"></div>
CSS
#chatscreen {
height: 100px;
overflow: scroll;
border: 1px solid #000;
}
Javascript
$(function(){
// Now let's load our messages
function load_messages(){
$( "#chatscreen" ).append( "<br>Test" );
}
var out = document.getElementById("chatscreen");
var c = 0;
var add = setInterval(function() {
// allow 1px inaccuracy by adding 1
var isScrolledToBottom = out.scrollHeight - out.clientHeight <= out.scrollTop + 1;
load_messages();
// scroll to bottom if isScrolledToBotto
if(isScrolledToBottom) {out.scrollTop = out.scrollHeight - out.clientHeight; }
}, 1000);
setInterval(updateScroll,30);
});
预览Igor的解决方案
投资组合
与Bootstrap 5:
< span style=" font - family:宋体;max-height: 300 px;" > < div > <!——你这里的内容——> < / div > < / div >
这里有一个基于Ryan Hunt博客文章的解决方案。它取决于overflow-anchor CSS属性,该属性将滚动位置固定在滚动内容底部的元素上。
function addMessage() { const $message = document.createElement('div'); $message.className = 'message'; $message.innerText = `Random number = ${Math.ceil(Math.random() * 1000)}`; $messages.insertBefore($message, $anchor); // Trigger the scroll pinning when the scroller overflows if (!overflowing) { overflowing = isOverflowing($scroller); $scroller.scrollTop = $scroller.scrollHeight; } } function isOverflowing($el) { return $el.scrollHeight > $el.clientHeight; } const $scroller = document.querySelector('.scroller'); const $messages = document.querySelector('.messages'); const $anchor = document.querySelector('.anchor'); let overflowing = false; setInterval(addMessage, 1000); .scroller { overflow: auto; height: 90vh; max-height: 11em; background: #555; } .messages > * { overflow-anchor: none; } .anchor { overflow-anchor: auto; height: 1px; } .message { margin: .3em; padding: .5em; background: #eee; } <section class="scroller"> <div class="messages"> <div class="anchor"></div> </div> </section>
注意,overflow-anchor目前在Safari中不起作用。