NervJS / taro

开放式跨端跨框架解决方案,支持使用 React/Vue/Nerv 等框架来开发微信/京东/百度/支付宝/字节跳动/ QQ 小程序/H5/React Native 等应用。 https://taro.zone/
https://docs.taro.zone/
Other
35.36k stars 4.77k forks source link

通过 onTouchMove 事件设置 transform 时会存在卡顿问题 #10540

Open ickg5 opened 2 years ago

ickg5 commented 2 years ago

相关平台

微信小程序

复现仓库

https://github.com/taroify/taro3312-distance 小程序基础库: 2.20.1 使用框架: React

复现步骤

通过 onTouchMove 事件设置 transform 时会存在卡顿问题

export default function Index() {
  const [distance, setDistance] = useState(0)

  function onTouchMove(event: ITouchEvent) {
    const {clientY} = event.touches[0]
    setDistance(clientY)
  }

  return (
    <View className='index' onTouchMove={onTouchMove} style={{
      transform: distance >= 0 ? `translate3d(0,${distance}px, 0)` : "",
    }}
    >
      <Text>Hello world!</Text>
    </View>
  )
}
.index {
  background: red;
  height: 50px * 2;
}

安卓真机测试时,向下滑动时会存在卡顿问题。iOS真机测试没有问题。

卡帧演示

非卡帧演示

当触屏向下滑动时会卡顿,但是当先向上在向下滑动时就不卡顿了。

期望结果

在安卓真机上,向下滑动不卡顿

实际结果

在安卓真机上,向下滑动卡顿

环境信息

� Taro v3.3.12

  Taro CLI 3.3.12 environment info:
    System:
      OS: Windows 10
    Binaries:
      Node: 14.17.1 - C:\Programs\nodejs\node-v14.17.1-win-x64\node.EXE
      Yarn: 1.22.11 - C:\Programs\nodejs\node\yarn.CMD
      npm: 6.14.13 - C:\Programs\nodejs\node-v14.17.1-win-x64\npm.CMD
lupingW commented 2 years ago

节流一下 touchmove 16.7毫秒一次 然后加一下tansition: transform 0.1s

ickg5 commented 2 years ago

节流一下 touchmove 16.7毫秒一次 然后加一下tansition: transform 0.1s

import {ITouchEvent, Text, View} from '@tarojs/components'
import * as _ from 'lodash'
import {useMemo, useState} from "react";
import './index.scss'

// eslint-disable-next-line import/no-commonjs
const lodashRoot = require("lodash/_root")

if (!lodashRoot.Date) {
  lodashRoot.Date = Date
}

export default function Index() {
  const [distance, setDistance] = useState(0)

  const touchMove = useMemo(() => _.throttle((event: ITouchEvent) => {
    const {clientY} = event.touches[0]
    setDistance(clientY)
  }, 16.7), [])

  return (
    <View
      className='index'
      onTouchMove={touchMove}
      style={{
        transition: 'transform 0.1s',
        transform: distance >= 0 ? `translate3d(0,${distance}px, 0)` : "",
      }}
    >
      <Text>Hello world!</Text>
    </View>
  )
}

我试了一下好像不行。

liuhuapiaoyuan commented 2 years ago

实测有效 @tgioer

import useThrottleFn from '@/hooks/lib/useThrottleFn';
import {ITouch, ITouchEvent, Text, View} from '@tarojs/components'
import {useCallback, useRef, useState} from "react";

export  function TouchTest() {
  const [translate,setTranslate] = useState<{translateX:any,translateY:any}>()
  const startPoint = useRef<ITouch>()
  const onTouchStart= useCallback((e:ITouchEvent)=>{
    startPoint.current  = e.touches[0]
    e.stopPropagation()
  },[])

  const touchMove = useThrottleFn((e: ITouchEvent) => {
    if(!startPoint.current){return }
    const endPoint = e.touches[e.touches.length - 1]
    const translateX = endPoint.pageX - startPoint.current?.pageX
    const translateY = endPoint.pageY - startPoint.current?.pageY
    setTranslate({ translateX, translateY })
  }, {wait:16.7})

  const onTouchCancel = useCallback(()=>{
    startPoint.current  = undefined
  },[])
  return (
    <View
      catchMove
      onTouchCancel={onTouchCancel}
      onTouchEnd={onTouchCancel}
      onTouchStart={onTouchStart}
      className='w-15 h-15 rounded-lg fixed z-10 left-5 bottom-5 bg-primary-light'
      onTouchMove={touchMove.run}
      style={{
        transition: 'transform 10ms',
        transform: translate ? `translate3d(${translate.translateX}px, ${translate.translateY}px , 0)` : "",
      }}
    >
      <Text className='text-white'>Hello world!</Text>
    </View>
  )
}

使用方,增加CustomWrapper,减少setData的嵌套

 <CustomWrapper>

        <TouchTest />
      </CustomWrapper>
ickg5 commented 2 years ago

@liuhuapiaoyuan @lupingW 感谢两位大佬,有效。

Nick742037091 commented 8 months ago

我对比了一下h5、微信开发者工具、安卓真机和iOS真机上面onTouchMove的回调次数,安卓真机明显很少。所以并不是transfrom卡顿,而是onTouchMove回调次数少,导致触发位移的次数少,看起来移动就卡顿了。

Nick742037091 commented 8 months ago

参考这两篇这篇文章 1、https://developers.weixin.qq.com/community/develop/doc/00042cb0458f70b6b9c72aef85bc00?_at=1558774452627) 2、https://taro-docs.jd.com/docs/react-overall#%E4%BA%8Ccatchmove

得使用小程序的catch:touchmove以捕获更多的触摸移动事件,在Taro React中对应的是加上catchMove属性