Vue3+Cropper.js扩展h5移动端双指旋转

新建useCropperTouch.js

javascript 复制代码
// 导出一个函数,用于处理触摸事件,配合cropper.js
export function useCropperTouch(cropperRef) {
  // 定义是否正在触摸的变量
  let isTouching = false
  // 定义初始角度
  let startAngle = 0
  // 定义初始距离
  let startDistance = 0
  // 定义当前旋转角度
  let currentRotate = 0
  // 定义当前缩放比例
  let currentScale = 1

  // 处理触摸开始事件
  const handleTouchStart = (e) => {
    // 如果触摸点数为2且Cropper存在
    if (e.touches.length === 2 && cropperRef.value) {
      // 设置正在触摸
      isTouching = true
      // 获取两个触摸点
      const [touch1, touch2] = e.touches

      // 计算初始角度
      startAngle = Math.atan2(touch2.clientY - touch1.clientY, touch2.clientX - touch1.clientX)

      // 计算初始距离
      startDistance = Math.hypot(touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY)

      // 获取当前状态
      const data = cropperRef.value.getData()
      currentRotate = data.rotate || 0
      currentScale = data.scaleX || 1
    }
  }

  // 处理触摸移动事件
  const handleTouchMove = (e) => {
    // 如果正在触摸且触摸点数为2且Cropper存在
    if (isTouching && e.touches.length === 2 && cropperRef.value) {
      // 阻止默认事件
      e.preventDefault()
      // 获取两个触摸点
      const [touch1, touch2] = e.touches

      // 计算当前角度
      const currentAngle = Math.atan2(
        touch2.clientY - touch1.clientY,
        touch2.clientX - touch1.clientX
      )

      // 计算当前距离
      const currentDistance = Math.hypot(
        touch2.clientX - touch1.clientX,
        touch2.clientY - touch1.clientY
      )

      // 计算旋转角度变化
      const rotateDelta = (currentAngle - startAngle) * (180 / Math.PI)
      // 计算缩放比例变化
      const scaleDelta = currentDistance / startDistance

      // 直接应用到 Cropper
      cropperRef.value.rotateTo(currentRotate + rotateDelta)
      cropperRef.value.scale(currentScale * scaleDelta)

      // 更新初始值
      startAngle = currentAngle
      startDistance = currentDistance
      currentRotate += rotateDelta
      currentScale *= scaleDelta
    }
  }

  // 处理触摸结束事件
  const handleTouchEnd = () => {
    // 设置不再触摸
    isTouching = false
  }

  // 设置事件监听
  const setup = (element) => {
    if (!element) return

    element.addEventListener('touchstart', handleTouchStart)
    element.addEventListener('touchmove', handleTouchMove, { passive: false })
    element.addEventListener('touchend', handleTouchEnd)
  }

  // 移除事件监听
  const cleanup = (element) => {
    if (!element) return

    element.removeEventListener('touchstart', handleTouchStart)
    element.removeEventListener('touchmove', handleTouchMove)
    element.removeEventListener('touchend', handleTouchEnd)
  }

  // 在组件卸载前移除事件监听
  onBeforeUnmount(() => {
    if (cropperRef) {
      cleanup(cropperRef)
    }
  })

  // 返回设置和清理函数
  return { setup, cleanup }
}

使用:

javascript 复制代码
import { useCropperTouch } from '@/components/useCropperTouch'

const cropper = ref(null)
const { setup } = useCropperTouch(cropper)

// 设置触摸事件,viewImgRef为触摸图片的ref
setup(viewImgRef.value.parentElement)