react函数式组件实现图片放缩拖拽

文章讲述了在React项目中如何实现图片预览组件,包括图片的放缩、拖拽功能,遇到的问题如鼠标事件处理和获取原始图片尺寸,以及解决方法,如使用useEffect和回调函数处理图片样式调整。
摘要由CSDN通过智能技术生成

在项目中遇到这样一个需求,需要实现一组图片的预览,要求图片可以放缩、拖拽。并且在点击左侧目录切换到下一张图片时使得初始时居中

实现效果如下:页面左侧为图片集预览菜单,通过点击左侧缩略图,右侧出现该图片的预览内容。核心功能在于右侧预览组件,该组件允许用户使用鼠标移动和放大/缩小图像。图像最初位于其父容器的中心,可以分别通过单击、拖动或滚动鼠标滚轮来更改其位置和缩放级别。

当时遇到的问题主要有两个,一是对react封装的鼠标事件不熟悉,二是对于切换到下张图片时如何获取图片的原始宽高,进而将其居中显示。

组件接口定义:

interface ImageDraggerProps {
  selectedItem: Photo;
}

Photo是后端定义的单个图片数据类型。从上层组件中传给图片预览组件。

export interface Photo {
  /**
   * 图片名称
   */
  name: string;
  /**
   * 图片地址
   */
  url: string;
}

首先是如何在切换图片时获取原始宽高进行下一步操作。

解决方法是结合useEffect和回调函数,在当前选中的图片发生改变时执行useEffect,在useEffect中再执行回调函数,通过回调函数获取图片宽高后改变图片的样式,这样就避免了直接在useEffect中执行函数的异步问题。

// 回调函数
const getImgNaturalStyle = (
  img: HTMLImageElement,
  callback: (width: number, height: number) => void,
) => {
  if (img.naturalWidth) {
    // modern browsers
    callback(img.naturalWidth, img.naturalHeight);
  } else {
    // IE6/7/8
    const image = new Image();
    image.src = img.src;
    image.onload = function () {
      callback(image.width, image.height);
    };
  }
};

useDeepCompareEffect(() => {
    const img: HTMLImageElement = document.querySelector(
      `#img${selectedItem?.name.replace(/\./g, '_')}`,
    );
    getImgNaturalStyle(img, (width, height) => {
      img.style.left = `calc(50% - ${width / 2}px)`;
      img.style.top = `calc(50% - ${height / 2}px)`;
    });
    setZoom(1.0);
  }, [selectedItem?.name]);

接下来是实现图片放缩拖拽的部分:功能分为放缩和拖拽两个部分,通过不同的函数实现。

图片拖拽的核心是move函数,它是一个事件处理程序,当用户单击图像时调用它。允许用户通过用鼠标单击和拖动图像在其父容器中移动图像。

// Move image function
  const move = (e: React.MouseEvent<HTMLElement>) => {
    e.preventDefault();
    // 获取元素
    const wrapper = document.querySelector(
      `#wrapper${selectedItem?.name.replace(/\./g, '_')}`,
    ) as HTMLElement;
    const img: any = document.querySelector(`#img${selectedItem?.name.replace(/\./g, '_')}`);
    const x = e.pageX - img.offsetLeft;
    const y = e.pageY - img.offsetTop;
    // 添加鼠标移动事件
    wrapper.addEventListener('mousemove', moveImg);
    function moveImg(p: any) {
      img.style.left = p.pageX - x + 'px';
      img.style.top = p.pageY - y + 'px';
    }
    // 添加鼠标抬起事件,鼠标抬起,将事件移除
    img.addEventListener('mouseup', function () {
      wrapper.removeEventListener('mousemove', moveImg);
    });
    // 鼠标离开父级元素,把事件移除
    wrapper.addEventListener('mouseout', function () {
      wrapper.removeEventListener('mousemove', moveImg);
    });
  };

图片缩放的核心是rollImg函数,当用户滚动鼠标滚轮而光标在图像的父容器上时调用该函数,即给图片的外部div设置属性onWheel={rollImg}:

 // Roll image function
  const rollImg = (e: React.WheelEvent<HTMLElement>) => {
    /* 获取当前页面的缩放比 若未设置zoom缩放比,则为默认100%,即1,原图大小 */
    let scale: number = zoom;
    /* 获取滚轮滚动值并将滚动值叠加给缩放比zoom deltaY变动值单位为±124,其中负数表示为向上滚动,正数表示向下滚动 */
    scale -= e.deltaY / 1240;
    /* 最小范围 和 最大范围 的图片缩放尺度 */
    if (scale >= 0.2 && scale <= 5) {
      setZoom(scale);
    }
    return false;
  };

当时还遇到一个小问题,有一张图片上传之后发现无法显示,之后发现是CSS的id选择器除了要满足唯一性之外,需要以字母开头而且之间不能有.这个符号。而那张图片的命名是pic.1。

所以对图片的id做了如下处理:

<img
  id={`img${selectedItem?.name.replace(/\./g, '_')}`}
  onMouseDown={move}
  src={buildCosUrl(selectedItem?.url)}
  draggable={true}
  alt=""
  className={styles.image}
  style={{
    WebkitTransform: `scale(${zoom})`,
    left: `0px`,
    top: `0px`,
  }}
/>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值