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

需求

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

使用前端框架是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

相关推荐
孤舟蓑影7 分钟前
2024最新(API 12)鸿蒙开发面试题-HarmonyOS Next
前端·学习·华为·typescript·harmonyos·鸿蒙·鸿蒙系统
小鼠米奇14 分钟前
小程序的数据驱动和vue的双向绑定有何异同?
前端·vue.js·小程序
真的很上进16 分钟前
前端速通面经八股系列(二)—— HTML篇
前端·html
YUMI~Aloogy@com1 小时前
Axios介绍;前后端分离开发的介绍;YAPI的使用;Vue项目简介、入门;Elementui的使用;nginx介绍
java·前端·javascript·ajax·java-ee·maven
陈两全2 小时前
CSS笔记
前端·css·笔记
ohMyGod_1232 小时前
打卡52天------图论(应用题)
前端·javascript·算法
JackieZhengChina2 小时前
如何评估Redis的性能
前端·数据库·redis
2401_836571002 小时前
前端学习Day32
前端
ohMyGod_1232 小时前
打卡51天------图论(深搜/广搜应用题)
前端·javascript·算法
程序者王大川2 小时前
【后端学前端】纯HTML实现响应式布局
前端·css·学习·html