今天的项目任务中实现一个瀑布流,点击图片可以实现图片预览、左右切换效果。说干就干,下班时,提交完代码准备溜时,提出一个新需求,在预览图片时添加一个上下滑动取消预览的效果,唉,加吧,我爱加班。
这里主要记录一下实现该功能的关键步骤,如下:
一、页面结构
以下是页面结构内容,css样式及组件内容不在此赘述
<template>
<div>
<halo-dialog class="preview-image" :visible="visible" @cancel="close">
<swiper zoom lazy class="swiper-outer" :current="swiperIndex" @swiper="onSwiper" @slideChange="changeIndex">
<swiper-slide v-for="(item, key) in computedList" :key="item.key || key">
<div
class="swiper-zoom-container"
@touchstart="getTouchstartY"
@touchmove="getTouchmove"
@touchend="touchEnd"
:style="transformStyle"
>
<img :data-src="`${item.path}-w1242.jpg`" class="swiper-lazy" />
<div class="swiper-lazy-preloader swiper-lazy-preloader-white"></div>
</div>
</swiper-slide>
</swiper>
<div class="close-outer" @click.stop="close">
<img src="./images/close_icon.png" class="close" />
</div>
</halo-dialog>
</div>
</template>
二、触摸事件概述
预览图片时,移动端界面通过触摸事件来判断是否滑动
事件名称 | 描述 | 是否包含 touches 数组 |
---|---|---|
touchstart | 触摸开始,多点触控,后面的手指同样会触发 | 是 |
touchmove | 接触点改变,滑动时 | 是 |
touchend | 触摸结束,手指离开屏幕时 | 是 |
每个触摸事件都包括了三个触摸列表,每个列表里包含了对应的一系列触摸点(用来实现多点触控):
- touches:当前位于屏幕上的所有手指的列表。
- targetTouches:位于当前DOM元素上手指的列表。
- changedTouches:涉及当前事件手指的列表。
每个 Touch 对象包含的属性如下:
- clientX:触摸目标在视口中的x坐标。
- clientY:触摸目标在视口中的y坐标。
- identifier:标识触摸的唯一ID。
- pageX:触摸目标在页面中的x坐标。
- pageY:触摸目标在页面中的y坐标。
- screenX:触摸目标在屏幕中的x坐标。
- screenY:触摸目标在屏幕中的y坐标。
- target:触摸的DOM节点目标。
三、功能实现
<script>
export default {
data() {
return {
startY: 0,
startX: 0,
imgScale: 1,
touchAngle: 0,
moveY: 0,
moveX: 0,
transformStyle: {}
}
},
methods: {
getTouchstartY(e) {
if (e.targetTouches.length === 1) {
// 初始style
this.transformStyle = {
transition: ""
};
// 获取触摸目标在视口中的位置
this.startY = e.targetTouches[0].clientY;
this.startX = e.targetTouches[0].clientX;
}
},
getTouchmove(e) {
if (this.prevent) {
e.preventDefault();
}
if (e.targetTouches.length === 1) {
// 获取滑动的距离
this.moveY = e.targetTouches[0].clientY - this.startY;
this.moveX = e.targetTouches[0].clientX - this.startX;
// 设置图片缩放的大小
this.imgScale = 1 - Math.abs(this.moveY) / 500;
// 触摸滑动角度
this.touchAngle = Math.abs(this.moveY / this.moveX);
if (this.touchAngle > 1) {
this.transformStyle = {
transform: `translate(${this.moveX}px,${this.moveY}px) scale(${this.imgScale})`
};
}
}
},
touchEnd() {
if (this.touchAngle > 1) {
// 如果触摸滑动的距离大于130px,就关闭图片,关闭弹窗
if (Math.abs(this.moveY) > 130) {
this.transformStyle = {
transform: "scale(0)",
transition: "all .5s"
};
setTimeout(() => {
this.close();
}, 200);
} else {
// 如果触摸滑动的距离未超过130px,实现图片还原
this.transformStyle = {
transform: "translateY(0) scale(1)",
transition: "all 0.2s"
};
}
}
}
}
}
</script>
四、实现效果
动态效果图可以参照https://live.photoplus.cn/live/65097362?nw=live#/live