1、思路:
因为offsetTop、scrollTop等不属于css属性,所以这些无法用css动画或过度来实现。首先想到的是使用position + top 定位结合 transition 来实现。
2、效果:

3、原生代码:
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title></title> <script language="javascript" type="text/javascript"> window.onload=function(){ var boxContainer = document.getElementById('boxContainer'); var ulList = document.getElementById('ulList'); var ulListLen = ulList.children.length; var speed = 3000;//移动速度,值越大速度越慢 var timer = null;//定时器 var liHeight = 30;//li列表的高度 function marquee() { console.log(ulList.offsetTop, ulList.style.top) if (ulList.offsetTop <= -(liHeight * (ulListLen - 1))){//判断复制的信息是否到达box的最左边 ulList.style.top = 0; ulList.style.transition = 'none'; marquee(); }else { ulList.style.transition = 'all .5s ease-in-out'; ulList.style.top = (ulList.offsetTop - liHeight) + 'px'; } } timer = setInterval(marquee, speed);//设置定时器 } </script> <style> #boxContainer{ overflow:hidden; height:32px; width:300px; border:1px solid #000; position: relative; } .liItems{ width: 300px; height: 30px; line-height: 30px; text-align: center; } #ulList{ list-style-type: disc; margin-block: 0; margin-inline: 0; padding-inline: 0; position: absolute; top: 0; /* transition: all .5s ease-in-out; */ } </style> </head> <body> <div id="boxContainer"> <ul id="ulList"> <li class="liItems">人生在世须尽欢 莫使金樽空对月</li> <li class="liItems">我寄愁心与明月,随风直到夜郎西</li> <li class="liItems">不是花中偏爱菊,此花开尽更无花</li> <li class="liItems">辛苦遭逢起一经,干戈寥落四周星</li> <li class="liItems">山河破碎风飘絮,身世浮沉雨打萍。</li> <li class="liItems">惶恐滩头说惶恐,零丁洋里叹零丁。</li> <li class="liItems">人生自古谁无死?留取丹心照汗青。</li> <!-- 将第一条信息复制 --> <li class="liItems">人生在世须尽欢 莫使金樽空对月</li> </ul> </div> </body> </html>
4、封装使用在react项目中:
import React, { useEffect, useRef } from 'react';
import { experimentalStyled } from '@material-ui/core';
import moment from 'moment';
import PropTypes from 'prop-types';
moment.locale('zh-cn');
const MainLayoutContent = experimentalStyled('div')({
margin: '0 5px',
overflow: 'hidden',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
});
function WorldCarousel({
dataList,
liHeight,
speed,
}) {
const boxContentRef = useRef();
const ulRef = useRef();
const timerRef = useRef();
const marquee = () => {
const ulListLen = ulRef.current.children.length;
if (ulRef.current.offsetTop <= -(liHeight * (ulListLen - 1))) { // 判断复制的信息是否到达box的最左边
ulRef.current.style.top = 0;
ulRef.current.style.transition = 'none';
marquee();
} else {
ulRef.current.style.transition = 'all .5s ease-in-out';
ulRef.current.style.top = `${ulRef.current.offsetTop - liHeight}px`;
}
};
const setEffectFunction = () => {
timerRef.current = setInterval(marquee, speed * 1000);
};
const removeEffectFunction = () => {
clearInterval(timerRef.current);
};
useEffect(() => {
console.log({ boxContentRef });
timerRef.current = setInterval(marquee, speed * 1000); // 设置定时器
boxContentRef.current.onmouseenter = removeEffectFunction;
boxContentRef.current.onmouseleave = setEffectFunction;
return () => {
clearInterval(timerRef.current);
};
}, []);
const content = () => {
dataList?.push(dataList[0]);
return dataList.map((item, index) => (
<li
key={(index === (dataList.length - 1)) ? 'firstDataCope' : item.data}
style={{
'100%',
height: liHeight,
lineHeight: `${liHeight}px`,
textAlign: 'center',
fontSize: '18px',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}}
>
<span>{ item.content }</span>
<span>{ moment(item.data).fromNow() }</span>
</li>
));
};
return (
<MainLayoutContent>
<div
ref={boxContentRef}
style={{
overflow: 'hidden',
height: `${liHeight}px`,
'100%',
border: 0,
position: 'relative'
}}
>
<ul
ref={ulRef}
style={{
'100%',
listStyleType: 'disc',
marginBlock: 0,
marginInline: 0,
paddingInline: 0,
position: 'absolute',
top: 0
}}
>
{ content() }
</ul>
</div>
</MainLayoutContent>
);
}
WorldCarousel.propTypes = {
dataList: PropTypes.array, // 数据列表
liHeight: PropTypes.number, // 移动速度,值越大速度越慢
speed: PropTypes.number, // li列表的高度
};
WorldCarousel.defaultProps = {
dataList: [],
liHeight: 30,
speed: 3,
};
export default WorldCarousel;
5、使用:
const dataList = [ { data: 20200101, address: '杭州', content: '元旦抓娃娃开心啊', }, { data: 20200202, address: '杭州', content: '二月二,炒大豆', }, { data: 20200303, address: '杭州', content: '西湖美景,三月天哎', }, { data: 20200404, address: '杭州', content: '愚人节快乐', }, { data: 20200505, address: '杭州', content: '五月,我们来啦', }, { data: 202006066, address: '杭州', content: '六月的雨,下个不停...', }, ]; <WorldCarousel dataList={dataList} liHeight={60} speed={3} />
6、效果展示:
