import Taro from '@tarojs/taro'
import { View, ITouchEvent } from '@tarojs/components'
import React, { useEffect, useState, useRef } from 'react'
import cs from 'classnames'
import './index.scss'
const WindowInfo = Taro.getWindowInfo()
//设计稿px转真实px
// const getRenderPx = (value) => {
// return (value / 750) * WindowInfo.screenWidth
// }
interface IProps {
className?: string
children?: React.ReactNode
initPosition?: { x: number; y: number }
style?: React.CSSProperties
}
// type PropertyOf<T> = T extends { initPosition: infer initPosition } ? initPosition : never
type Position = { x: number; y: number }
type IdomSize = { width: number; height: number }
const Slide = (props: IProps) => {
const { style, className = '', children, initPosition = { x: 0, y: 0 } } = props
const [position, setPosition] = useState<Position>(initPosition)
const domSizeRef = useRef<IdomSize>({ width: 0, height: 0 })
const handleTouchMove = (e: ITouchEvent) => {
const { width, height } = domSizeRef.current
const x = e.touches[0].clientX
const y = e.touches[0].clientY
const coordinate = { x, y }
// 元素宽度为width,这里应该是WindowInfo.windowWidth - width,但是下面有矫正逻辑会减去width/2,所以这里应该是width/2
if (x > WindowInfo.windowWidth - width / 2) {
coordinate.x = WindowInfo.windowWidth - width / 2
}
if (x < 0) {
coordinate.x = 0
}
//和上面一样本来也是WindowInfo.windowHeight - height/2
if (y > WindowInfo.windowHeight - height / 2) {
coordinate.y = WindowInfo.windowHeight - height / 2
}
if (y < 0) {
coordinate.y = 0
}
//下面可以理解成矫正处理,如果直接是使用coordinate.x,它代表的是悬浮球左上角的坐标,为了让鼠标坐标为悬浮球的中心点,那么就需要 coordinate.x - width/2
//这样悬浮球就跟着手势走
if (coordinate.x - width / 2 > 0) {
coordinate.x = coordinate.x - width / 2
} else {
coordinate.x = 0
}
if (coordinate.y - height / 2 > 0) {
coordinate.y = coordinate.y - height / 2
} else {
coordinate.y = 0
}
setPosition(coordinate)
}
const onClick = () => {}
useEffect(() => {
Taro.nextTick(() => {
Taro.createSelectorQuery()
.select('#demo')
.boundingClientRect()
.exec((res) => {
domSizeRef.current = res[0]
})
})
}, [])
const classNames = cs('my-slide', className)
const mergeStyle = {
...style,
transform: `translate(${position.x}px, ${position.y}px)`,
}
return (
<View id="demo" onTouchMove={handleTouchMove} style={mergeStyle} className={classNames} catchMove onClick={onClick}>
{children && children}
</View>
)
}
export default Slide
.my-slide {
background-color: #2f80ed;
position: fixed;
z-index: 100;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
使用
<Slide className="mytest" style={{ backgroundColor: 'pink' }}>
<View>1111</View>
</Slide>