Pinch-Zoom 实现移动端手势放大+旋转
外部库的使用
pinchzoom.js
优势:这个库已经封装好了手势的放大,缩小,移动,等一系列功能
劣势:需要我们手动添加旋转和重置图片的功能
pinchzoom.js的使用
npm i pinch-zoom-js && yarn add pinch-zoom-js 复制代码
import PinchZoom from 'pinch-zoom-js' 复制代码
let el = document.querySelector('#my-id'); let pz = new PinchZoom(el, options); 复制代码
可配置项
属性 | 说明 | 默认值 |
---|---|---|
tapZoomFactor | 双击缩放的倍数 | 2 |
zoomOutFactor | 缩放低于这个值的时候调整为原始大小 | 1.3 |
animationDuration | 动画持续时间(毫秒) | 300 |
maxZoom | 最大放大倍数 | 4 |
minZoom | 最小缩小吧倍数 | 0.5 |
draggableUnzoomed | 即使图像未缩放,也可以捕获拖动事件 | true |
lockDragAxis | 将图元的平移锁定到单个轴 | false |
setOffsetsOnce | 仅计算一次偏移(容器内的图像位置) | false(使用'true'在连续的'load'和'resize'上保持偏移) |
use2d | 空闲时返回到二维变换 | true |
verticalPadding | 图像周围应用的垂直填充 | 0 |
horizontalPadding | 图像周围应用的水平填充 | 0 |
onZoomStart | 开始缩放的事件 | null |
onZoomEnd | 停止缩放的事件 | null |
onZoomUpdate | 更新缩放元素的回调 | null |
onDragStart | 开始拖动元素 | null |
onDragEnd | 结束拖动元素 | null |
onDragUpdate | 更新拖动位置 | null |
onDoubleTap | 双击图片 | null |
事件
let pz = new PinchZoom(myElement); pz.enable(); // 启用所有手势捕捉(默认启用) pz.disable(); // 禁用所有手势捕捉(默认启用) 复制代码
回调示例
var myElement = document.getElementById("myElement"); var pz = new PinchZoom.default(myElement, { draggableUnzoomed: false, minZoom: 1, onZoomStart: function(object, event){ }, onZoomEnd: function(object, event){ } }) 复制代码
添加旋转事件
第一步:我们先写一个方法,给图片元素dom设置一下transform属性,每次旋转90度
//this.vhtmlRotate用于记录旋转的角度默认是0 let vhtmlImage = document.getElementById('vhtmlImage'); let scale = vhtmlImage.offsetHeight / vhtmlImage.offsetWidth; if (this.vhtmlRotate % 180) { scale = 1; } vhtmlImage.style.transform = `scale(${scale},${scale}) rotate(${this.vhtmlRotate +90}deg)` 复制代码
问题:每次旋转的时候图片都会变成原始大小,再被Pinch-Zoom设定缩放,会有一个图片闪烁的问题
解决方案:旋转之前先把图片变成透明,旋转后再放出来
vhtmlImage.style.opacity = `0`; ........ vhtmlImage.style.opacity = `1`; 复制代码
问题:放大图片后点击旋转,会出现图片位置错误,影响使用,由于Pinch-Zoom并没有重置组件的方法,如果使用v-if重新渲染和new组件,会导致产生多个pinch-zoom-container
标签,导致拖动闪烁,具体原因未知
解决方案:在看了组件源码以后发现update方法,它可以更新给组件设置的参数,我们就在组件加载完成后记录图片位置和放大的尺寸(这里默认是1),旋转后手动设置,然后调用update的方法
this.PinchZoom.zoomFactor = 1; this.PinchZoom.offset = me.offset; this.PinchZoom.update(); 复制代码
问题:多次快速点击旋转,会导致页面报错,原因是组件并没有渲染完成,就进行了下一次渲染
解决方案:手动防抖事件
// 防止快速多次点击 if (!PinchZoomFinish) { return; } PinchZoomFinish = false; ....... PinchZoomFinish = true; 复制代码
完整代码
<template> <div class="car-recognition"> <div id="pinc_zoom_room"> <div id="image_room"> <img id="vhtmlImage" src="https://assets.che300.com/feimg/m/banner/banner_weibao2.png" alt="" /> </div> </div> <div @click="resetImg" class="reset_img">旋转图片</div> </div> </template> <script> import PinchZoom from 'pinch-zoom-js'; let PinchZoomFinish = true; export default { name: 'carRecognition', data() { return { vhtmlRotate: 0, offset:{} }; }, methods: { //重置图片 resetImg() { let me = this; // 防止快速多次点击 if (!PinchZoomFinish) { return; } PinchZoomFinish = false; let vhtmlImage = document.getElementById('vhtmlImage'); vhtmlImage.style.opacity = `0`; let scale = vhtmlImage.offsetHeight / vhtmlImage.offsetWidth; if (me.vhtmlRotate % 180) { scale = 1; } vhtmlImage.style.opacity = `1`; vhtmlImage.style.transform = `scale(${scale},${scale}) rotate(${me.vhtmlRotate + 90}deg)`; me.vhtmlRotate = me.vhtmlRotate + 90; me.PinchZoom.zoomFactor = 1; me.PinchZoom.offset = me.offset; me.PinchZoom.update(); PinchZoomFinish = true; }, }, created() { setTimeout(() => { const el = document.getElementById('image_room'); this.PinchZoom = new PinchZoom(el, { zoomOutFactor: 0.5, onZoomStart: function(object, event){ console.log(object,event,'onZoomStart') }, onZoomEnd: function(object, event){ console.log(object,event,'onZoomEnd') }, onZoomUpdate: function(object, event){ // console.log(object,event,'onZoomUpdate') }, onDragStart: function(object, event){ console.log(object,event,'onDragStart') }, onDragEnd: function(object, event){ console.log(object,event,'onDragEnd') }, onDragUpdate: function(object, event){ // console.log(object,event,'onDragUpdate') }, onDoubleTap: function(object, event){ console.log(object,event,'onDoubleTap') } }); this.$nextTick(()=>{ this.offset = this.PinchZoom.offset console.log(this.offset) }) },200) } }; </script> <style lang="less"> #pinc_zoom_room { text-align: left; height: 7rem; margin: 0.4rem; position: relative; background: #cccccc; border-radius: 0.066667rem; -webkit-touch-callout: none; /*系统默认菜单被禁用*/ -webkit-user-select: none; /*webkit浏览器*/ -khtml-user-select: none; /*早期浏览器*/ -moz-user-select: none; /*火狐*/ -ms-user-select: none; /*IE10*/ user-select: none; #vhtmlImage { max-height: 7rem; -webkit-touch-callout: none; } } </style>
作者:三百云技术中心
链接:https://juejin.cn/post/7047000739712860173