js实现列表自动向上滚动
方案一、js控制dom的margin-top减小
注意:复制一份滚动内容,滚到最后的时候不会留白,然后让margin-top归零实现重复滚动
/**
* javascript原生自动滚动
* @param domId 需要实现这个效果的domId
* @param height 行高
* @param speed 滚动速度,默认34,约30帧
* @param delay 间隔多久滚动一行
*/
auroRiseScrolling(domId, height, speed = 33, delay = 1000) {
let dom = document.getElementById(domId);
// 判断内容是否超过容器高度需要滚动
if (dom.offsetHeight <= dom.parentElement.offsetHeight) return;
let stop = false; // 暂停滚动
let t;
dom.style.marginTop = '0';
dom.innerHTML += dom.innerHTML; // 复制一份滚动内容,
//鼠标移入,停止滚动
dom.onmouseover = () => { stop = true; };
//鼠标移出,继续滚动
dom.onmouseout = () => { stop = false; };
setTimeout(start, delay); // delay(1s)以后start()开始滚动
function start() {
t = setInterval(scrolling, speed); // speed(0)时间内向上滚动1px
// 未停止时候,需要marginTop-1px,下面scrolling()里面的if()才会未为true,才能滚动,反之则会执行elese,清除上一次的timer,就不会滚动了
if (!stop) dom.style.marginTop = `${parseInt(dom.style.marginTop) - 1}px`;
}
function scrolling() {
// 判断是否滚动了一行的高度,滚了一行之后,if内容为true
if (parseInt(dom.style.marginTop) % height !== 0) {
dom.style.marginTop = `${parseInt(dom.style.marginTop) - 1}px`; // margin-top -= 1px ,向上滚动1px
// dom.scrollHeight元素内容高度,由于前面复制了一份内容,所有当滚动高度为它的一半时候,代表滚完了,此时将marginTop归零(因为后一半内容和前面一样,肉眼看不出变化,实际上瞬间回到了顶部)
if (Math.abs(parseInt(dom.style.marginTop)) >= dom.scrollHeight / 2) dom.style.marginTop = '0';
} else {
// 一行滚动结束,开始准备新的一行滚动
clearInterval(t);
setTimeout(start, delay);
}
}
}
TEMPLATE
<template>
<div class="auto-scroll-box">
<ul id="autoScroll">
<li v-for="num in 20"> {{num}} </li>
</ul>
</div>
</template>
STYLE
<style scoped>
.auto-scroll-box {
width: 200px;
height: 400px;
margin: 0 auto;
overflow: hidden;
}
/* 行高 */
.auto-scroll-box > ul > li {
height: 2rem;
}
/* 偶数行加个背景颜色 */
.auto-scroll-box > ul > li:nth-child(odd) {
background-color: #42b983;
}
</style>
** 这里有两个小坑 **
- 尽可能的加载偶数行,复制的第一题内容和原本的第一条内容就一个奇数行一个偶数行,可能导致样式不同,出现闪烁效果。
- 如果显示器刷新频率低于144hz,不建议滚动速度过快,会出现抖动现象
开箱即用的完整demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* { margin: 0; padding: 0; }
li { list-style-type: none; }
.auto-scroll-box { width: 200px; height: 200px; border: 2px dotted #ccc; margin: 2rem auto; overflow: hidden; }
.auto-scroll-box>ul>li { height: 2rem; line-height: 2rem; }
.auto-scroll-box>ul>li:nth-child(odd) { background-color: #42b983; }
</style>
<title>自动向上滚动</title>
</head>
<body>
<div class="auto-scroll-box">
<ul id="autoScroll">
<li> 1 </li>
<li> 2 </li>
<li> 3 </li>
<li> 4 </li>
<li> 5 </li>
<li> 6 </li>
<li> 7 </li>
<li> 8 </li>
<li> 9 </li>
<li> 10 </li>
</ul>
</div>
<script>
auroRiseScrolling('autoScroll', 32, 100, 0);
function auroRiseScrolling(domId, height, speed = 0, delay = 1000) {
let dom = document.getElementById(domId);
if (dom.offsetHeight <= dom.parentElement.offsetHeight) return;
let stop = false;
let t;
dom.style.marginTop = '0';
dom.innerHTML += dom.innerHTML;
dom.onmouseover = () => {
stop = true;
};
dom.onmouseout = () => {
stop = false;
};
setTimeout(start, delay);
function start() {
t = setInterval(scrolling, speed);
if (!stop) dom.style.marginTop = `${parseInt(dom.style.marginTop) - 1}px`;
}
function scrolling() {
if (parseInt(dom.style.marginTop) % height !== 0) {
dom.style.marginTop = `${parseInt(dom.style.marginTop) - 1}px`;
if (Math.abs(parseInt(dom.style.marginTop)) >= dom.scrollHeight / 2) dom.style.marginTop = '0';
} else {
clearInterval(t);
setTimeout(start, delay);
}
}
}
</script>
</body>
</html>