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={{
width: '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`,
width: '100%',
border: 0,
position: 'relative'
}}
>
<ul
ref={ulRef}
style={{
width: '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、效果展示:

