【一】實現效果:實現雙指縮放以及單指移動下面圖片中的內容

【二】:實現思路
通過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/