vue手势缩放组件

原理解析(不想看原理的朋友可以直接跳到开发步骤)

关于手势缩放,最重要的点在于如何监听手势;如何获取缩放比例;如何在缩放的同时,保证双指之间的中心点一直处于原来的位置。

首先,手势的监听可以使用如下方法:

document.addEventListener('touchstart touchmove touchend', function(e) {
    if (e.touches.length == 2) { 
	    //双指触摸手势事件  
	} 
}

缩放比例 = 开始触摸时两指间距离 / 触摸结束时两指间距离。得到缩放比例后使用transform: scale(x,y)进行缩放。

最难的是,如何保证缩放的同时,双指之间的中心点一直处于原来的位置:

假设双指之间的中心点的坐标为(x,y),则缩放k倍后,其在缩放后的坐标系中坐标为(kx, ky);

两点间的位移距离为: 水平位移sx = x – kx;  垂直位移sy = y - ky; 那么想要双指之间的中心点回到原来的位置就必须使用transform: translate(sx,sy); 平移回去。

其中,双指中心点x坐标 = (第一个手指的x坐标 - 第二个手指的x坐标)/ 2,y坐标 = (第一个手指的y坐标 - 第二个手指的y坐标)/ 2。

这里我们使用hammer.js插件,不需要自己去计算缩放比例和双指中心点,使用更简单方便。

hammer.js简介

支持的手势有:pan滑动,缩放pinch,按压press,旋转rotate,轻扫swipe,点击tap,详细属性见下官网截图:

使用方法示例:

//通过ref获取dom元素
let zoomEl = this.$refs.zoom;
//初始化hammer
var hammer = new Hammer(zoomEl);
//缩放事件默认是关闭的,需要设置启用
hammer.get('pinch').set({ enable: true });
//监听缩放事件
hammer.on("pinchmove pinchstart pinchin pinchout",e => {
    //e.type   事件类型,如pinchmove
    //e.scale  缩放比例
    //e.center 触摸点的中心
    //e.deltaX X轴偏移
    //e.deltaY Y轴偏移
});

事件对象完整属性:

好了,铺垫这么多,接下来该一步步实现缩放效果了,开发步骤如下:

一、安装hammer.js插件

npm install hammerjs --save

二、dom元素布局

<template>
	<div ref="test" class="test">
		<img src="https://whbj-yellowpage.oss-cn-shenzhen.aliyuncs.com/e_seal/template/authorization_file.png" alt="">
	</div>
</template>

三、style样式设置

<style>
	.test{
		transform-origin: 0 0;
	}
	
	.test img{
		width: 100%;
		height: 100%;
	}
</style>

四、js监听手势实现缩放

这里我们把手势操作单独封装到一个js文件当中,如:zoom.js文件。

import Hammer from 'hammerjs'//引用hammerjs

//定义缩放方法,接收一个element参数:使用export暴露该方法
export function zoomElement(el){

	var x = 0;//x轴偏移
	var y = 0;//y轴偏移
	var lastScale = 1;//上次缩放值
	var currentScale = 1;//当前缩放值
	var center;//双指中心点
	
	//初始化hammer
	var hammer = new Hammer(el);
	//缩放事件默认是关闭的,需要设置启用
	hammer.get('pinch').set({ enable: true });
	
	//监听缩放事件
	hammer.on("pinchmove pinchstart pinchin pinchout",e => {
		//缩放开始时获取上一次缩放值与双指中心点
	    if(e.type == "pinchstart"){
	        lastScale = currentScale || 1;
			center = e.center;
			console.log("centerX:"+center.x)
			console.log("centerY:"+center.y)
	    }
		//当前缩放值 = 上一次缩放值 * 缩放比例
	    currentScale = lastScale * e.scale;
		
		//如果缩放值小于1,重置为1
		if (currentScale < 1){
			currentScale = 1;
		}
		
		//偏移量 = 双指中心点 - 当前缩放值 * 双指中心点 = 双指中心点 *(1-当前缩放值)
		x = center.x * (1-currentScale)
		y = center.y * (1-currentScale)
		
		//设置transform
	    el.style.transform="translateX("+(x)+"px)"+"translateY("+(y)+"px)"+"scale(" + (currentScale)+ ")"
	});
	//监听滑动事件
	hammer.on('panright panleft panup pandown',(e)=>{
		//滑动时:偏移量 = 滑动距离 + 当前偏移量
		var translateX = e.deltaX + x
		var translateY = e.deltaY + y
		//如果偏移X值大于0:表示视图已经滑到最左侧,重置为0
		if (translateX > 0){
			translateX = 0
		}
		//如果偏移Y值大于0:表示视图已经滑到最顶部,重置为0
		if (translateY > 0){
			translateY = 0
		}
		//如果偏移X值小于(屏幕宽度-元素宽度):表示视图已经滑到最左侧,重置为0
		//屏幕宽度 = el.clientWidth
		//元素宽度 = el.getBoundingClientRect().width
		if (translateX < el.clientWidth - el.getBoundingClientRect().width){
			translateX = el.clientWidth - el.getBoundingClientRect().width
		}
		//如果偏移Y值大于(屏幕高度-元素高度):表示视图已经滑到最左侧,重置为0
		//屏幕高度 = el.clientHeight
		//元素高度 = el.getBoundingClientRect().height
		if (translateY < el.clientHeight - el.getBoundingClientRect().height){
			translateY = el.clientHeight - el.getBoundingClientRect().height
		}
		//设置transform
	    el.style.transform="translateX("+(translateX)+"px)"+"translateY("+(translateY)+"px)"+"scale(" + (currentScale)+ ")"
	});
	hammer.on('panend',(e)=>{
		//滑动结束:记录当前偏移量 
	    x = e.deltaX + x;
	    y = e.deltaY + y;
	    console.log("panendx:"+x)
	    console.log("panendy:"+y)
	})
}

五、引用zoom.js文件,传入需要缩放的组件。

<script>
	import {zoomElement} from '@/assets/static/js/zoom.js';
	
	export default {
		name: 'zoom',
		data() {
			return {
				
			};
		},
		mounted() {
			//获取需要缩放的dom元素
			let zoomEl = this.$refs.test;
			console.log("zoomEl:"+zoomEl)
			zoomElement(zoomEl)
		}
	}
	
</script>

大功告成!

 

Logo

前往低代码交流专区

更多推荐