先定一个小目标:放大镜🔍效果实现(React + TS)

1,254 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情

原文在此:juejin.cn/post/710822…

早上打开掘金刷文章的时候,看到了这个

图片.png

心里想着,那我试一下吧。不用,对于移动端的部分,这边我也没有进行尝试。防抖的部分,大家可以自己实现一个函数,也可以使用现成的 loadsh 进行包装。

原理原文作者已经讲得很明白了。

主要讲一下React 和 jq 一些不同的地方

  1. HTML 结构中的 class 需要换成 className。
  2. 获取元素,在 React Hooks 中使用 useRef + ref 来实现。
  3. 绑定鼠标事件,直接在元素上,使用 onMouseEnter,onMouseLeave,onMouseMove。
<>
      <div className="container">
        <div className="place"></div>
        <div className="inner">
          <img
            width={200}
            height={200}
            ref={originImg}
            src="https://cdn.pixabay.com/photo/2022/02/23/14/50/houses-7030773__340.jpg"
            onMouseEnter={onMouseEnter}
          />
        </div>
      </div>
      <div
        className="zoom-holder"
        style={{
          left: newData.left,
          top: newData.top,
          display: showPalce ? 'block' : 'none'
        }
        }>
        <div className="img_wrapper">
          <img
            ref={newinImg}
            style={{
              left: newImgData.left,
              top: newImgData.top
            }}
            src="https://cdn.pixabay.com/photo/2022/02/23/14/50/houses-7030773__340.jpg"
          />
        </div>
      </div>
      <div
        ref={zoomOverlay}
        onMouseLeave={onMouseLeave}
        onMouseMove={onMouseMove}
        className="zoom-img-overlay"
        style={{
          left: orgImg.left,
          top: orgImg.top,
          width: orgImg.width,
          height: orgImg.height
        }}
      ></div>
    </>
  1. 使用 useState 来存储数据
const zoomOverlay = useRef<HTMLDivElement>(null);
  const originImg = useRef<HTMLImageElement>(null);
  const newinImg = useRef<HTMLImageElement>(null);
  const [orgImg, setOrgImg] = useState<Obj>({
    left: 0,
    top: 0,
    width: 0,
    height: 0
  });
  const [newImg, setNewImg] = useState<Obj2>({
    width: 0,
    height: 0
  });
  const [newData, setNewData] = useState<Obj1>({
    left: 0,
    top: 0
  });
  const [newImgData, setNewImgData] = useState<Obj1>({
    left: 0,
    top: 0
  })
  const [showPalce, setShowPalce] = useState<boolean>(false);

当触发事件的时候,改变位置

原来的文章中使用 zoomOverlay.css('left') ,这里我们使用 zoomOverlay?.current?.offsetLeft!。 对于 topwidthheight ,我们也是进行同样的操作。

const onMouseLeave = () => {
    setShowPalce(false);
  }

  const onMouseMove = (e: any) => {
    const moveX = e.pageX - zoomOverlay?.current?.offsetLeft!;
    const moveY = e.pageY - zoomOverlay?.current?.offsetTop!;
    const lastX = moveX / (orgImg?.width! / newImg?.width!);
    const lastY = moveY / (orgImg?.height! / newImg?.height!);

    setNewData({
      left: e.pageX - 150,
      top: e.pageY - 150
    })
    setNewImgData({
      left: -(lastX - 150),
      top: -(lastY - 150)
    })
    setShowPalce(true);
  }

  const onMouseEnter = () => {
    setOrgImg({
      left: originImg?.current?.offsetLeft!,
      top: originImg?.current?.offsetTop!,
      width: originImg?.current?.offsetWidth!,
      height: originImg?.current?.offsetHeight!
    });
    setNewImg({
      width: newinImg?.current?.width!,
      height: newinImg?.current?.height!
    });
  }

写到最后,其实发现,代码还是有点冗余的。不过,算是实现了基本的效果吧。

图片.png