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 20px', overflow: 'hidden', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', }); function WorldCarousel({ dataList, liHeight, speed, liWidth }) { 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(() => { timerRef.current = setInterval(marquee, speed * 1000); // 设置定时器 boxContentRef.current.addEventListener('mouseenter', removeEffectFunction); boxContentRef.current.addEventListener('mouseleave', setEffectFunction); return () => { clearInterval(timerRef.current); boxContentRef.current.removeEventListener('mouseleave', setEffectFunction); boxContentRef.current.removeEventListener('mouseenter', removeEffectFunction); }; }, []); const content = () => { dataList?.push(dataList[0]); return dataList.map((item, index) => ( <li key={(index === (dataList.length - 1)) ? 'firstDataCope' : item.data} style={{ width: liWidth, height: liHeight, lineHeight: `${liHeight}px`, textAlign: 'center', fontSize: '18px', }} > <span>{ item.content }</span> <span>{ moment(item.data, 'YYYYMMDD').fromNow() }</span> </li> )); }; return ( <MainLayoutContent> <div ref={boxContentRef} style={{ overflow: 'hidden', height: `${liHeight}px`, width: liWidth, border: 0, position: 'relative' }} > <ul ref={ulRef} style={{ listStyleType: 'disc', marginBlock: 0, marginInline: 0, paddingInline: 0, position: 'absolute', top: 0 }} > { content() } </ul> </div> </MainLayoutContent> ); } WorldCarousel.propTypes = { dataList: PropTypes.array, // 数据列表 liHeight: PropTypes.number, // 移动速度,值越大速度越慢 liWidth: PropTypes.number, // 宽度 speed: PropTypes.number, // li列表的高度 }; WorldCarousel.defaultProps = { dataList: [], liHeight: 30, liWidth: 300, 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、效果展示: