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