阅读量:0
需求
点击图片,出现一个蒙版和图片,双指捏合可以使图片放大或缩小。
使用前端框架是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