需求
点击图片,出现一个蒙版和图片,双指捏合可以使图片放大或缩小。
使用前端框架是svelte,但是不影响,功能都是JS实现。
代码
相关定义:
import {
onMount, afterUpdate, onDestroy } from 'svelte';
let imgDetailRef;
let initialDistance = 0;
let initialScale = 1;
let currentScale = 1;
定义监听事件触发的方法:
scale(${currentScale})
是缩放相关的样式。
const getDistanceBetweenTouches = (ev) => {
let [touch1, touch2] = ev.touches;
return Math.sqrt(
Math.pow(touch1.pageX - touch2.pageX, 2) +
Math.pow(touch1.pageY - touch2.pageY, 2),
);
};
const touchStartHandler = function (ev) {
if (ev.touches.length === 2) {
initialDistance = getDistanceBetweenTouches(ev);
initialScale = currentScale;
}
};
const touchMoveHandler = function (ev) {
// 防止出现Infinity
if (ev.touches.length === 2 && initialDistance !== 0) {
let distance = getDistanceBetweenTouches(ev);
if (distance !== initialDistance) {
currentScale = (initialScale * distance) / initialDistance;
// 最多只能缩小到原本大小
if (currentScale < 1) currentScale = 1;
imgDetailRef.style.transform = `translate(-50%, -50%) scale(${
currentScale})`;
}
}
};
const touchEndHandler = function (ev) {
initialDistance = 0;
initialScale = currentScale;
};
在生命周期中定义事件监听与销毁:
定义在afterUpdate
中:我们点击图片会显示一个蒙版,图片显示在蒙版上,允许放大和缩小。因此,点击图片时才渲染这个蒙版,imgDetailRef
对应的div是条件渲染,若在onMount
中定义此事件的监听,此时可能不存在imgDetailRef
。
若存在imgDetailRef
,要先把之前定义的监听移除(removeEventListener
),否则会不断地触发监听事件,表示为:当手指捏合操作图片的放大和缩小时,图片的变化显得很卡,且控制台输出一堆信息(console.log
写在touchMoveHandler
)中。
afterUpdate(() => {
if (imgDetailRef) {
imgDetailRef.removeEventListener('touchstart', touchStartHandler, false);
imgDetailRef.removeEventListener('touchmove', touchMoveHandler, false);
imgDetailRef.removeEventListener('touchend', touchEndHandler, false);
imgDetailRef.addEventListener('touchstart', touchStartHandler, false);
imgDetailRef.addEventListener('touchmove', touchMoveHandler, false);
imgDetailRef.addEventListener('touchend', touchEndHandler, false);
}
});
onDestroy(() => {
if (imgDetailRef) {
imgDetailRef.removeEventListener('touchstart', touchStartHandler, false);
imgDetailRef.removeEventListener('touchmove', touchMoveHandler, false);
imgDetailRef.removeEventListener('touchend', touchEndHandler, false);
}
});
至于蒙版和图片:点击图片时showImageDetail=true
等,简单逻辑不赘述。
{:else if showImageDetail}
<div>
<img class="img-detail" id="img-detail" bind:this={imgDetailRef} src={selectedImage} alt="selectedImage" />
</div>
{/if}
如果想在蒙层出现时不允许蒙层下的内容滚动:给不想滚动的类加上此样式(会回到页面顶部)
.no-scroll {
position: fixed;
width: 100%;
}
或让body
的overflow:hidden
文章评论