Taro实现dom跟着手势滑动

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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值