React 移动端 单指移动 双指缩放图片或者DOM标签


【一】实现效果:实现双指缩放以及单指移动下面图片中的内容

【二】:实现思路

通过onTouchStart onTouchMove onTouchEnd onTouchCancel 四个react自带的触屏方法,获取event,通过event.touches可以知道是单指还是双指,如果event.touches里面是一个对象,则是单指,如果存在第二个对象,则是双指,存储对应点击坐标,用到Math.hypot 三角函数 计算直角三角形的斜边,用现在移动的 除以 之前存储的  就是一个缩放比例, 记住缩放比例,用于下次缩放,给DoM对象添加transform:scale(缩放比例)  就可以了,额,说的有点乱,可能我还是没太理解好,不过还是实现了,具体可以看下代码

【三】:实现代码

function Map(){
    const [transform, setTransform] = useState('')
    const [positionLeft, setPositionLeft] = useState(0)
    const [positionTop, setPositionTop] = useState(0)
    const [mapRef, setMapRef] = useState({})
    const [pageX, setPageX] = useState(0)
    const [pageY, setPageY] = useState(0)
    const [store] = useState({scale: 1})


    const handleTouchStart = (event) => {
        let touches = event.touches;
        let events = touches[0];//单指
        let events2 = touches[1];//双指
        if(touches.length == 1){
            console.log('出手对付对付', mapRef, event)
            // 单指操作
            let pageX = Number(events.pageX);
            let pageY = Number(events.pageY);
            setPageX(pageX)
            setPageY(pageY)
            store.moveable = true;
            setPositionLeft(mapRef.style.left)
            setPositionTop(mapRef.style.top)
        }else{
            // 第一个触摸点的坐标
            store.pageX = events.pageX;
            store.pageY = events.pageY;
            store.moveable = true;
            if (events2) {
                store.pageX2 = events2.pageX;
                store.pageY2 = events2.pageY;
            }
            store.originScale = store.scale || 1;
        }
    }

    const handleTouchMove = (event) => {
        if (!store.moveable) {
            return;
        }
        let touches = event.touches;
        let events = touches[0];
        let events2 = touches[1];
        if (touches.length == 1) {
            let pageX2 = Number(events.pageX);
            let pageY2 = Number(events.pageY);
            //控制图片移动
            setPositionLeft(positionLeft + pageX2 - pageX)
            setPositionTop(positionTop + pageY2 - pageY)
        } else {
            // 双指移动
            if (events2) {
                // 第2个指头坐标在touchmove时候获取
                if (!store.pageX2) {
                    store.pageX2 = events2.pageX;
                }
                if (!store.pageY2) {
                    store.pageY2 = events2.pageY;
                }

                // 获取坐标之间的距离
                let getDistance = function(start, stop) {
                    //用到三角函数
                    return Math.hypot(stop.x - start.x,
                        stop.y - start.y);
                };
                // 双指缩放比例计算
                let zoom = getDistance({
                    x : events.pageX,
                    y : events.pageY
                }, {
                    x : events2.pageX,
                    y : events2.pageY
                }) / getDistance({
                    x : store.pageX,
                    y : store.pageY
                }, {
                    x : store.pageX2,
                    y : store.pageY2
                });
                // 应用在元素上的缩放比例
                let newScale = store.originScale * zoom;
                // 最大缩放比例限制
                if (newScale > 15) {
                    newScale = 15;
                }
                // 记住使用的缩放值
                store.scale = newScale;
                // 图像应用缩放效果
                setTransform('scale(' + newScale + ')')
            }
        }

    }

    const handleTouchEnd = (e) => {
        store.moveable = false;
        delete store.pageX2;
        delete store.pageY2;
    }

    const handleTouchCancel = (e) => {
        store.moveable = false;
        delete store.pageX2;
        delete store.pageY2;
    }

    

    
}

 和

<div className="mapBox">
    // 移动的对象 <div style={{width: '100%', height:'4.6rem', display: 'flex', alignItems: 'center', justifyContent: 'center',touchAction: 'none',transition: 'all 0.3s ease-out', transform: transform, position: 'absolute', top: positionTop + 'px', left: positionLeft + 'px'}} ref={e => {setMapRef(e)}} onTouchStart={handleTouchStart} onTouchMove={handleTouchMove} onTouchEnd={handleTouchEnd} onTouchCancel={handleTouchCancel} > // 内容 </div> </div>
  

【四】:补充

用于声明事件监听的时候设置为主动事件监听,要不会报以下错误【Unable to preventDefault inside passive event listener invocation】

方法一:拖动的对象上添加了touchAction:none 用于去除滑动时默认现象产生,但不影响事件触发

方法二:window.addEventListener('touchmove', func, { passive: false })  加上 passive:false  

 

更具体可以看代码来源网址:https://www.freesion.com/article/49151231665/


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM