【前端】原生实现图片的放大与缩放

需求

点击图片,出现一个蒙版和图片,双指捏合可以使图片放大或缩小。

使用前端框架是svelte,但是不影响,功能都是JS实现。

代码

相关定义:

javascript 复制代码
  import { onMount, afterUpdate, onDestroy } from 'svelte';
  
  let imgDetailRef;
  let initialDistance = 0;
  let initialScale = 1;
  let currentScale = 1;

定义监听事件触发的方法:

scale(${currentScale})是缩放相关的样式。

javascript 复制代码
  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)中。

javascript 复制代码
  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等,简单逻辑不赘述。

html 复制代码
{:else if showImageDetail}
 <div>
   <img
     class="img-detail"
     id="img-detail"
     bind:this={imgDetailRef}
     src={selectedImage}
     alt="selectedImage"
   />
 </div>
{/if}

如果想在蒙层出现时不允许蒙层下的内容滚动:给不想滚动的类加上此样式(会回到页面顶部)

css 复制代码
.no-scroll {
    position: fixed;
    width: 100%;
  }

或让bodyoverflow:hidden

相关推荐
life码农5 分钟前
HTML文本换行显示几种方法总结
前端·html
强子感冒了6 分钟前
CSS基础学习:CSS选择器与优先级规则
前端·css·学习
啟明起鸣14 分钟前
【Nginx 网关开发】上手 Nginx,简简单单启动一个静态 html 页面
运维·c语言·前端·nginx·html
vortex517 分钟前
深度字典攻击(实操笔记·红笔思考)
前端·chrome·笔记
我是伪码农19 分钟前
Vue 1.30
前端·javascript·vue.js
利刃大大27 分钟前
【Vue】默认插槽 && 具名插槽 && 作用域插槽
前端·javascript·vue.js
艳阳天_.30 分钟前
web 分录科目实现辅助账
开发语言·前端·javascript
小白64021 小时前
2025年终总结-迷途漫漫,终有一归
前端·程序人生
烟花落o1 小时前
贪吃蛇及相关知识点讲解
c语言·前端·游戏开发·贪吃蛇·编程学习
晚霞的不甘1 小时前
Flutter for OpenHarmony专注与习惯的完美融合: 打造你的高效生活助手
前端·数据库·经验分享·flutter·前端框架·生活