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

需求

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

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

或让body的overflow:hidden

相关推荐
IT_陈寒几秒前
React实战技巧总结:如何优雅处理复杂列表的渲染卡顿问题?
前端·人工智能·后端
ZoeLandia3 分钟前
React11:数据请求与 TanStack Query
前端·react.js·typescript·react
前端架构师-老李14 分钟前
HTML与CSS基础第二课—初识HTML
前端·css·html
视***间15 分钟前
视程空间Edge工业边缘盒:给工业机器人装一颗耐造的“本地大脑“
前端·edge·机器人·边缘计算·智慧工业·工业视觉·视程空间
Dovis(誓平步青云)16 分钟前
一个分区超温就全棚浇水,控制系统怎样按区下策略
开发语言·前端·javascript·人工智能·机器学习
Sailing30 分钟前
🚀🚀【封闭结束5】Agent 中的 SSE 流式推送与 HITL 暂停恢复
前端·面试·agent
java1234_小锋32 分钟前
【技术专题】CSS3 网页技术 - CSS3 单位、颜色、字体与文本
前端·css·css3
biaov41 分钟前
Jenkins + Docker 搭建前端 CI:前端一键打包部署
前端·docker·jenkins