【一】实现效果:实现双指缩放以及单指移动下面图片中的内容
【二】:实现思路
通过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