tsx
import React,{ useCallback, useEffect, useRef, useState } from 'react'
import list_Data from './data'
import './index.scss'
interface listData {
userName: string,
text: string,
likes: number
}
const SlideListItemModel = ({ data,onClose}: { data: listData ,onClose:()=>void}) => {
let { userName, text, likes } = data
return (
<div className='list-item-model'>
<div onClick={onClose} className="list-item-model-close">关闭</div>
<div>{userName}</div>
<div>{text}</div>
<div>{likes}</div>
</div>
)
}
const SlideListItem = ({ data,autoScroll }: { data: listData,autoScroll:()=>void }) => {
let { userName, text, likes } = data
let [isShow, setIsShow] = useState(false)
const showModel = () => {
setIsShow(true)
}
const closeModel = () => {
setIsShow(false)
autoScroll()
}
return (
<>
<div className='slide-list-item' onClick={showModel}>
<div className='slide-list-item-avatar'>
<img
className='slide-list-item-avatar-img'
src={"https://p26-passport.byteacctimg.com/img/user-avatar/1e1b1258b43b135af6a1c7b591ab95b5~300x300.image"}
alt="" />
</div>
<div className='slide-list-item-info'>
<div className='slide-list-item-info-head'>
<div className='slide-list-item-info-username'>{userName}</div>
<div className='slide-list-item-info-likes'>{likes}</div>
</div>
<div className='slide-list-item-info-content'>
{text}
</div>
</div>
</div>
{
isShow && <SlideListItemModel data={data} onClose={closeModel}/>
}
</>
)
}
const SlideList = ({ data }: {
data: listData[]
}) => {
let adata = [...data.slice(0, 10), ...data.slice(0, 10)]
let [isScrolling, setIsScrolling] = useState(true)
let wrapper = useRef<HTMLDivElement>(null)
let timer = useRef<number>()
useEffect(() => {
let step = 1
const render = () => {
if (wrapper.current) {
wrapper.current.scrollLeft += step;
if (wrapper.current.offsetWidth + wrapper.current.scrollLeft >= wrapper.current.scrollWidth / 2) {
wrapper.current.scrollLeft %= wrapper.current.scrollWidth / 2;
}
timer.current = window.requestAnimationFrame(render)
}
}
isScrolling && render()
return () => {
timer.current && window.cancelAnimationFrame(timer.current)
}
}, [isScrolling]);
const MouseDown = useCallback(() => {
setIsScrolling(false)
}, [])
const autoScroll = useCallback(()=>{
let timer = setTimeout(() => setIsScrolling(true), 3000)
return () => {
clearTimeout(timer)
}
},[])
return (
<>
<div className="slide-list" ref={wrapper}
onMouseDown={MouseDown}
>
{
adata.map((i, index) => <SlideListItem key={index} data={i} autoScroll={autoScroll}/>)
}
</div>
</>
)
}
const App = ()=>{
console.log(list_Data);
return (
<div>
<SlideList data={list_Data}/>
</div>
)
}
export default ()=> <App/>
CSS
.slide-list{
margin: 0 auto;
height: 150px;
max-width: 375px;
background-image: linear-gradient(to top, #a18cd1 0%, #fbc2eb 100%);
display: flex;
flex-wrap: wrap;
flex-direction: column;
justify-content: center;
overflow: auto;
&::-webkit-scrollbar {
display: none;
}
.slide-list-item{
background-image: linear-gradient(to top, #a8edea 0%, #fed6e3 100%);
margin: 3px;
padding: 3px;
border: 1px solid #a18cd1;
border-radius: 5px;
display: flex;
background-color: white;
font-size: 8px;
min-width: 110px;
max-width: 150px;
height: 50px;
overflow: hidden;
.slide-list-item-avatar{
width: 40px;
height: 40px;
.slide-list-item-avatar-img{
width: 100%;
height: 100%;
}
}
.slide-list-item-info{
flex:1;
.slide-list-item-info-head{
height: 15px;
position: relative;
transform: scale(0.75);
.slide-list-item-info-username{
left: 5px;
position: absolute;
}
.slide-list-item-info-likes{
position: absolute;
right: 5px;
}
}
.slide-list-item-info-content{
height: 28px;
position: relative;
bottom: 2px;
line-height: 14px;
transform: scale(0.8);
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
}
}
}
.list-item-model{
position: absolute;
top: 80px;
left: 50%;
transform: translateX(-50%);
width: 325px;
height: 400px;
padding: 10px;
background-color: gainsboro;
z-index: 1;
border: #a18cd1 1px solid;
box-shadow: 0 0 3px 5px #a18cd1 ;
border-radius: 5px;
.list-item-model-close{
position: absolute;
right: 5px;
}
}
data
export default [
{
"userName": "加生准",
"text": "快将张列共民党青员回效意图非候美就结还科现太目般接。",
"likes": 2587
},
{
"userName": "都多音查",
"text": "接全力们统红却京信要原形队速取片改写必养象放步划确。",
"likes": 1201
},
{
"userName": "难及",
"text": "素日至感低候今口从那论合出情该得称面精。",
"likes": 12112
},
{
"userName": "老志率价",
"text": "西五按人市己处千此约山品进段以际交引动厂现再中必才。",
"likes": 546
},
{
"userName": "表低济准",
"text": "劳族除就是斗需车再没指山导自难流题的达节低务以队资确。",
"likes": 2359
},
{
"userName": "治其农据极",
"text": "装国至接价权确被都经亲法口省率美低我老办。",
"likes": 6793
},
{
"userName": "是节",
"text": "基等权书一军表还率中切亲称生值备。",
"likes": 1541
},
{
"userName": "月种型代",
"text": "段米了算离连队记如决九养他几持系领须等价带。",
"likes": 5389
},
{
"userName": "条务立",
"text": "文专去自应于同般情称会许江无应变分候置划都引统。",
"likes": 9311
},
{
"userName": "金月强",
"text": "难无和阶通金眼自干么算如为斗各近身水真证况全。",
"likes": 16010
}
]