feat: add new component (AutoScrollContainer)

mack-mac
mackt 8 months ago
parent 9d1102c1b3
commit f0c00aa830

@ -3,6 +3,8 @@ import { useState } from 'react';
import Image from 'next/image'; import Image from 'next/image';
import { AutoScrollContainer } from '@/components';
export default function AudioPlayer({ className }: { className?: string }) { export default function AudioPlayer({ className }: { className?: string }) {
const [curTime, setCurTime] = useState('00:00'); const [curTime, setCurTime] = useState('00:00');
const [totalTime, setTotalTime] = useState('00:00'); const [totalTime, setTotalTime] = useState('00:00');
@ -16,14 +18,12 @@ export default function AudioPlayer({ className }: { className?: string }) {
{/* title & author */} {/* title & author */}
<div className="h-full ml-[27px] mr-[44px] py-[14px]"> <div className="h-full ml-[27px] mr-[44px] py-[14px]">
{/* 改成滚动的 */} <AutoScrollContainer hover width="140px" speed={50}>
<p className="w-[140px] text-[17px] leading-[23.8px] text-[rgba(0,0,0,0.95)] overflow-hidden whitespace-nowrap overflow-ellipsis truncate"> <div className="w-auto h-auto">
{'Ferrum Aeternum'} <p className="text-[17px] leading-[23.8px] text-[rgba(0,0,0,0.95)]">{'Ferrum Aeternumaaaaaaaaaaa'}</p>
</p> <p className="text-[13px] leading-[18.2px] text-[rgba(0,0,0,0.7)]">{'Ensiferum/mmmmsa'}</p>
{/* 改成滚动的 */} </div>
<p className="w-[140px] text-[13px] leading-[18.2px] text-[rgba(0,0,0,0.7)] overflow-hidden whitespace-nowrap overflow-ellipsis truncate"> </AutoScrollContainer>
{'Ensiferum/mmmmsa'}
</p>
</div> </div>
{/* progress bar */} {/* progress bar */}

@ -0,0 +1,90 @@
'use client';
/**
*
* TODO:
*/
import React, { useRef, useEffect, useState } from 'react';
interface TextScrollProps {
hover?: boolean;
speed?: number;
width: string;
className?: string;
children: React.ReactNode;
}
const TextScroll: React.FC<TextScrollProps> = ({
width = '100px',
className = '',
children = '',
hover = false,
speed = 30,
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const childrenRef = useRef<HTMLParagraphElement>(null);
const [isOverflowing, setisOverflowing] = useState<boolean>(false); // 子元素宽度是否溢出
const [isHovered, setIsHovered] = useState<boolean>(false); // 鼠标是否在 hover 状态
const [animation, setAnimation] = useState<string>(''); // 滚动动画
const handleMouseMove = (isMouseInside: boolean) => {
if (!hover) return; // 未传入 'hover = true' 时不响应鼠标事件
if (!childrenRef.current) return; // 获取不到 children 时不响应
if (isMouseInside && isHovered) return; // 鼠标已经进入时不响应
if (isMouseInside) {
childrenRef.current.style.animation = animation;
} else {
childrenRef.current.style.animation = '';
childrenRef.current.style.transform = 'translateX(0)';
}
setIsHovered(isMouseInside);
};
useEffect(() => {
const containerWidth = containerRef.current?.offsetWidth;
const childrenWidth = childrenRef.current?.offsetWidth;
if (containerWidth && childrenWidth && containerWidth < childrenWidth) {
setisOverflowing(true);
setAnimation(`scroll ${childrenWidth / speed}s linear infinite`);
if (!hover) childrenRef.current.style.animation = animation;
}
}, [children, speed, hover, animation]); // 当children变化时重新计算
return (
<div
ref={containerRef}
className={`relative h-auto overflow-hidden whitespace-nowrap`}
style={{ width }}
onMouseEnter={() => handleMouseMove(true)}
onMouseLeave={() => handleMouseMove(false)}
>
<div ref={childrenRef} className={`flex flex-row items-center relative w-[fit-content] h-auto ${className}`}>
{children}
{isOverflowing && (
<>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
{children}
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
</>
)}
</div>
<style jsx>{`
@keyframes scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-50%);
}
}
`}</style>
</div>
);
};
export default TextScroll;

@ -19,6 +19,7 @@ export { default as HotJournalList } from './Journal/HotJournalList';
// Common // Common
export { default as Input } from './common/Input'; export { default as Input } from './common/Input';
export { default as Button } from './common/Button'; export { default as Button } from './common/Button';
export { default as AutoScrollContainer } from './common/AutoScrollContainer';
// Audio Player // Audio Player
export { default as PlayerBar } from './AudioPlayer/PlayerBar'; export { default as PlayerBar } from './AudioPlayer/PlayerBar';

Loading…
Cancel
Save