为什么要自己写组件
- html中的标签可实现文字跑马灯效果,但这个标签在H5标准中已经被废弃,未来可能不受支持。
自定义的组件调整动画效果、性能方面更灵活,可以实现更多需求。
组件说明
- 本组件是基于React+hooks开发的,也可以改成vue的,动画原理一样。
- 组件可实现模拟标签的效果,也可使用css3动画获得更流畅的体验
- 参数说明:
v - 速度,每秒移动多少个像素,默认100
t - 刷新一次的时长(ms),默认50,只在frameWise为true时有效
frameWise - 为true即表示使用逐帧动画效果,内容运动过程中有振动的感觉;
为false则使用css3的过渡效果制作成动画,性能好,比较较流畅
使用举例
1. 模拟逐帧动画
<CssMarquee v={80}>{
list.map(item =>
<div className={'item'} onClick={() => gotoDetail(item)}>
<span className={'point'}>·</span>{item.content}
</div>
)}
</CssMarquee>
2. css3动画
<CssMarquee frameWise v={80} t={36}>{
list.map(item =>
<div className={'item'} onClick={() => gotoDetail(item)}>
<span className={'point'}>·</span>{item.content}
</div>
)}
</CssMarquee>
组件源码
import { useState, useEffect, useRef } from 'react'
export default ({ children, frameWise, v = 100, t = 50 }) => {
const wrapRef = useRef()
const contentRef = useRef()
const [offsetX, setOffsetX] = useState(0)
const _offsetX = useRef()
useEffect(() => {
frameWise && (_offsetX.current = offsetX)
})
useEffect(() => {
const wrapWidth = wrapRef.current.offsetWidth
const contentWidth = contentRef.current.scrollWidth
if (frameWise) {
setOffsetX(wrapWidth)
const timer = setInterval(() => {
if (-_offsetX.current > contentWidth) {
setOffsetX(wrapWidth)
} else {
setOffsetX(x => x - v * (t / 1000))
}
}, t)
return () => {
clearInterval(timer)
}
}
const deltaX = contentWidth + wrapWidth
const deltaT = deltaX / v + 's'
contentRef.current.style.transitionTimingFunction = 'linear'
const animation = () => {
contentRef.current.style['transition-duration'] = '0s'
contentRef.current.style.transform = `translateX(${wrapWidth}px)`
setTimeout(() => {
contentRef.current.style.transitionDuration = deltaT
contentRef.current.style.transform = `translateX(${-contentWidth}px)`
}, 100)
}
animation()
const timer = setInterval(() => {
animation()
}, deltaX * 1000 / v + 100)
return () => {
clearInterval(timer)
}
}, [])
return (children.length
? <div className={'m-cssMarquee'}>
<div className={'wrap'} ref={wrapRef}>{
frameWise
? <div className={'content'} ref={contentRef} style={{ transform: `translateX(${offsetX}px)` }}>{children}</div>
: <div className={'content'} ref={contentRef}>{children}</div>
}
</div>
</div>
: null
)
}