本文将介绍如何通过js实现移动端图片的 手势缩放,手势拖动,双击放大, 旋转等功能;
完成后的样例
外部库的使用
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>