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、效果展示: