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

需求

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

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

相关推荐
JarvanMo1 分钟前
如何在Dart 3.8中配置更新后的代码格式化工具
前端
yinshimoshen2 分钟前
根据S-T教学分析法绘制图形-前端实现
前端·canvas
五点六六六4 分钟前
一些关于TreeShaking的AST的理解
前端·javascript·前端工程化
清粥油条可乐炸鸡5 分钟前
tree 树组件大数据卡顿问题处理
前端
zhangxingchao27 分钟前
Android开发者如何快速上手Flutter开发
前端
空&白42 分钟前
css元素的after制作斜向的删除线
前端·css
海盐泡泡龟43 分钟前
“组件、路由懒加载”,在 Vue3 和 React 中分别如何实现? (copy)
前端·javascript·react.js
_揽1 小时前
html如何在一张图片上的某一个区域做到点击事件
前端·html
踢足球的,程序猿1 小时前
从 Vue 2.0 进阶到 Vue 3.0 的核心技术解析指南
前端·javascript·vue.js·前端框架·html
冷凌爱1 小时前
Fetch与Axios:区别、联系、优缺点及使用差异
前端·node.js·js