Taro(React)实现具有滚动效果的倒数计时器
Taro获取节点方法的封装
import Taro from "@tarojs/taro";
import { NodesRef } from "@tarojs/taro";
const selectorQueryClientRect = (selector:string) : Promise<NodesRef.BoundingClientRectCallbackResult> => {
return new Promise(resolve => {
const query = Taro.createSelectorQuery()
query.select(selector).boundingClientRect((res: NodesRef.BoundingClientRectCallbackResult) => {
resolve(res)
}).exec()
})
}
export {
selectorQueryClientRect
}
子组件
import { View } from "@tarojs/components"
import Taro from "@tarojs/taro";
import React, { CSSProperties, useEffect, useImperativeHandle, useState } from "react"
import { selectorQueryClientRect } from '../../util'
import "./index.css"
// props的接口
interface HPickItemProps {
list: Array<any>,
hclass?: string,
hstyle?: CSSProperties,
}
const HPickItem = React.forwardRef((props: HPickItemProps,ref) => {
// 对props的结构
const {
list,
hclass,
hstyle
} = props
const [move, setMove] = useState(0) // 滚动的距离
let [itemHeight,setItemHeight] = useState(0) // 单个模块的高度,即每次滚动的距离
// 对外暴露方法
const next = () => {
setMove(pre => pre - itemHeight)
}
const prev = () => {
setMove(pre => pre + itemHeight)
}
//用useImperativeHandle暴露一些外部ref能访问的属性
useImperativeHandle(ref, () => {
// 需要将暴露的接口返回出去
return {
next,
prev
};
})
// 挂载完毕后,获取元素的高度
useEffect(() => {
Taro.nextTick(async () => {
const { height: slidingHeight } = await selectorQueryClientRect('.sliding-container')
setItemHeight(slidingHeight / list.length)
})
}, [])
return (
<View className="sliding-container" ref={ref} style={{
position: 'relative',
top: `${move}px`,
transition: "top 0.5s ease-in-out"
}}>
{
list.map(value => <View className={hclass} style={hstyle}>{value}</View>)
}
</View>
)
})
export default HPickItem
父组件
import { View,Text } from "@tarojs/components"
import { useEffect, useRef, useState } from "react"
import HPickItem from "../../components/HPickItem/index"
import "./index.css"
const createList = (endNumber) => {
let res : Array<number> = []
for(let i = endNumber; i > 0; i--){
res.push(i)
}
return res
}
const relaxtion = (props) => {
let [relaxtionTime,setRelaxtionTime] = useState(15)
const controlRef = useRef(null)
const [pickList,setPickList] = useState(() => createList(15))
useEffect(() => {
const timer = setInterval(() => {
if(relaxtionTime === 0){
clearInterval(timer)
}
setRelaxtionTime(pre => pre - 1);
(controlRef.current as any).next()
},1000)
},[])
return(
<View className="container">
{}
<View className="countdown">
<HPickItem list={pickList} ref={controlRef}></HPickItem>
</View>
</View>
)
}
.countdown {
width: 80px;
height: 80px;
border-radius: 50%;
background-color: #F2F2FF;
box-shadow: 0 0 0 40px #E4E4FF;
font-size: 38px;
text-align: center;
line-height: 80px;
color: #3F498C;
float: right;
margin: 45px 45px 0 0;
overflow: hidden;
}