react如何实现缩放

发布时间:2022-12-28 10:44:30 作者:iii
来源:亿速云 阅读:526

这篇文章主要讲解了“react如何实现缩放”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“react如何实现缩放”吧!

react实现缩放的方法:1、监听onWheel事件;2、设置事件对象event的属性deltaY,当向上滚动时“deltaY<0”,向下滚动时“deltay>0”;3、修改每次滚动时缩放的比例,同时更改transform样式按比例进行缩放即可。

react图片缩放、平移(position、transform实现)

很多网页都会给文案附上一些图片补充描述,例如在说到地址时,会在旁边附上一张地图,并且在地图上标注该地址。如果附上的图片很小,很难看清楚地址的具体信息,有些产品经理会给图片设计一个可以平移、放大缩小的功能。本文将一一实现上述功能。

废话不多说,先给上效果图:

react如何实现缩放

主要三个功能点:

图片平移

图片平移可以监听这三个事件实现:onMouseDown、onMouseMove、onMouseUp
onMouseDown事件记录每次鼠标按下的坐标位置;
onMouseMove事件计算出每次平移的距离,该距离加上拖动前图片距离父元素的距离就等于拖动后图片相对于父元素的距离;
onMouseUp事件触发时,注销或者不让执行onMouseDown、onMouseMove事件,防止只要鼠标移入图片就会平移。

这三个事件需要阻止浏览器的默认行为,不然在移动时会自动打开图片。
react如何实现缩放

const WIDTH = 1200;const HEIGHT = 900;const DynamicStyle= () => {    
  const imgRef = React.createRef<HTMLImageElement>();  
  /** 图片样式 */  const [imgStyle, setImgStyle] = useState<React.CSSProperties>({});  /** 记录鼠标是否按下 */  const [mouseDowmFlag, setMouseDowmFlag] = useState(false);  /** 记录鼠标按下的坐标 */  const [mouseDowmPos, setMouseDowmPos] = useState<{x: number, y: number}>({x: 0, y: 0})  /** 鼠标可视区域时,重置鼠标按下的布尔值为false */  useEffect(() => {    document.onmouseover = () => {      if (mouseDowmFlag) {        setMouseDowmFlag(false);
      }
    };    return () => {      document.onmouseover = null;
    };
  }, [mouseDowmFlag])  /** 平移 */  const handleMouseDown = (event: React.MouseEvent<HTMLImageElement>) => {    const { clientX, clientY } = event;
    event.stopPropagation();
    event.preventDefault(); // 阻止浏览器默认行为,拖动会打开图片    setMouseDowmFlag(true); // 控制只有在鼠标按下后才会执行mousemove    setMouseDowmPos({      x: clientX,      y: clientY,
    });
  };  const handleMouseMove = (event: React.MouseEvent<HTMLImageElement>) => {
    event.stopPropagation();
    event.preventDefault();    const { clientX, clientY } = event;    const diffX = clientX - mouseDowmPos.x;    const diffY = clientY - mouseDowmPos.y;    if (!mouseDowmFlag || (diffX === 0 && diffY === 0)) return;    const { offsetLeft, offsetTop } = imgRef.current as HTMLImageElement;    const offsetX = parseInt(`${diffX + offsetLeft}`, 10);    const offsetY = parseInt(`${diffY + offsetTop}`, 10);    setMouseDowmPos({      x: clientX,      y: clientY,
    });    setImgStyle({
      ...imgStyle,      left: offsetX,      top: offsetY,
    });
  };  const handleMouseUp = (event: React.MouseEvent<HTMLImageElement>) => {
    event.stopPropagation();
    event.preventDefault();    setMouseDowmFlag(false);
  };  return (    <div className={styles.imgArea}>      <img 
        src={mapImg} 
        alt='part'        ref={imgRef}        height={HEIGHT} 
        style={imgStyle}        onMouseDown={handleMouseDown}        onMouseMove={handleMouseMove}        onMouseUp={handleMouseUp}
      >      </img>    </div>
  )
}

图片缩放

图片缩放可以监听onWheel事件,事件对象event有一个记录滚轮滚动的属性deltaY,当向上滚动时deltaY<0,向下滚动时deltaY>0。每次滚动修改其缩放的比例,同时更改transform样式按比例进行缩放。

react如何实现缩放

const WIDTH = 1200;const HEIGHT = 900;const SCALE = 0.2;const DynamicStyle= () => {  const imgRef = React.createRef<HTMLImageElement>();  /** 初始化缩放比例,默认为1 */  const [rate, setRate] = useState(1);  /** 图片样式 */  const [imgStyle, setImgStyle] = useState<React.CSSProperties>({});  /** 记录鼠标是否按下 */  const [mouseDowmFlag, setMouseDowmFlag] = useState(false);  /** 记录鼠标按下的坐标 */  const [mouseDowmPos, setMouseDowmPos] = useState<{x: number, y: number}>({x: 0, y: 0})  /** 图片现在大小 */  const [initial, setInitial] = useState<{width: number, height: number}>({width: WIDTH, height: HEIGHT});  useEffect(() => {    const { naturalWidth, naturalHeight, width, height } = imgRef.current as HTMLImageElement;    setInitial({ width, height });    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])  // console.log(natural, initial)  useEffect(() => {    document.onmouseover = () => {      if (mouseDowmFlag) {        setMouseDowmFlag(false);
      }
    };    return () => {      document.onmouseover = null;
    };
  }, [mouseDowmFlag])  /** 缩放 */  const handleWheelImage = (event: React.WheelEvent<HTMLImageElement>) => {    // 向上为负,向下为正    const bigger = event.deltaY > 0 ? -1 : 1;    // transform偏移量    const transformX = -initial.width / 2;    const transformY = -initial.height / 2;    if (bigger > 0 && rate < 2) {      const enlargeRate = rate + SCALE;      setImgStyle({
        ...imgStyle,        transform: `matrix(${enlargeRate}, 0, 0, ${enlargeRate}, ${transformX}, ${transformY})`, // 默认以图片中心为原点进行缩放
      });      setRate(enlargeRate);
    } else if (bigger < 0 && rate > 1) {      const shrinkRate = rate - SCALE;      setImgStyle({
        ...imgStyle,        transform: `matrix(${shrinkRate}, 0, 0, ${shrinkRate}, ${transformX}, ${transformY})`,
      });      setRate(shrinkRate);
    }
  }  /** 平移 */  const handleMouseDown = (event: React.MouseEvent<HTMLImageElement>) => {    const { clientX, clientY } = event;
    event.stopPropagation();
    event.preventDefault(); // 阻止浏览器默认行为,拖动会打开图片    setMouseDowmFlag(true); // 控制只有在鼠标按下后才会执行mousemove    setMouseDowmPos({      x: clientX,      y: clientY,
    });
  };  const handleMouseMove = (event: React.MouseEvent<HTMLImageElement>) => {
    event.stopPropagation();
    event.preventDefault();    const { clientX, clientY } = event;    const diffX = clientX - mouseDowmPos.x;    const diffY = clientY - mouseDowmPos.y;    if (!mouseDowmFlag || (diffX === 0 && diffY === 0)) return;    const { offsetLeft, offsetTop } = imgRef.current as HTMLImageElement;    const offsetX = parseInt(`${diffX + offsetLeft}`, 10);    const offsetY = parseInt(`${diffY + offsetTop}`, 10);    setMouseDowmPos({      x: clientX,      y: clientY,
    });    setImgStyle({
      ...imgStyle,      left: offsetX,      top: offsetY,
    });
  };  const handleMouseUp = (event: React.MouseEvent<HTMLImageElement>) => {
    event.stopPropagation();
    event.preventDefault();    setMouseDowmFlag(false);
  };  return (    <div className={styles.imgArea}>      <img 
        src={mapImg} 
        alt='part' 
        height={HEIGHT} 
        style={imgStyle}        ref={imgRef}        onWheel={handleWheelImage}        onMouseDown={handleMouseDown}        onMouseMove={handleMouseMove}        onMouseUp={handleMouseUp}
      >      </img>    </div>
  )
}
.imgArea {  position: relative;  width: 1200px;  height: 900px;  margin: auto;  border: 1px solid #da2727;  overflow: hidden;
  & > img {    position: absolute;    left: 50%;    top: 50%;    transform: translate(-50%, -50%);    cursor: move;
  }
}

如果没有设置transformOrigin,默认是相对于图片中心进行缩放,但是在初始为了让图片在可视区域内水平垂直居中,使用了transform: translate(-50%, -50%);,因此为了缩放时相对于图片中心点,需要设置matrix的第5、6个参数矫正transformOrigintransform: matrix(${shrinkRate}, 0, 0, ${shrinkRate}, ${transformX}, ${transformY})

车站标注

首先,定义一个常量表示图标的坐标,这个坐标是相对于原始图片左上角的定位。

const imgInfo = {  lableLeft: "1900",  lableTop: "2000",}

这里,解释一下原始图的概念:
react如何实现缩放

随便在网上查看一个图片元素,比如上面。1200 x 900是页面定的图片大小,但图片还有一个真实大小4535 x 3402。

要计算图标在没有平移缩放时的初始坐标之前,需要算出图片的缩放比例(不是上面的rate):

/** 图片原始大小,默认设置为1是防止计算图片原始大小与初始大小比例出现无穷大 */const [natural, setNatural] = useState<{width: number, height: number}>({width: 1, height: 1});/** 图片现在大小 */const [initial, setInitial] = useState<{width: number, height: number}>({width: WIDTH, height: HEIGHT});useEffect(() => {    const { naturalWidth, naturalHeight, width, height } = imgRef.current as HTMLImageElement;    setNatural({ width: naturalWidth, height: naturalHeight });    setInitial({ width, height });    // eslint-disable-next-line react-hooks/exhaustive-deps}, [])  
// 初始图片缩放比例(图片有原始的图片大小)const imgScaleRateX = initial.width / natural.width;const imgScaleRateY = initial.height / natural.height;

图标初始的坐标就可以计算出:

const labelLeft = parseInt(`${imgInfo.lableLeft}`, 10) * imgScaleRateX;const labelTop = parseInt(`${imgInfo.lableTop}`, 10) * imgScaleRateY;

当图片平移时,图标也需要跟着平移,这是的坐标计算:

// 图标相对父元素坐标 = 图标位置坐标 + 图片坐标const labelLeft = parseInt(`${imgInfo.lableLeft}`, 10) * imgScaleRateX + Number(imgStyle.left || WIDTH / 2);
const labelTop = parseInt(`${imgInfo.lableTop}`, 10) * imgScaleRateY + Number(imgStyle.top || HEIGHT / 2);

react如何实现缩放

当图片缩放时,图标需要随着图片一起缩放。如果没有对图标设置transformOrigin,默认时相对图标的中心缩放的。为了保证图标随着图片一起缩放,那就必须使得图片和图标的缩放参照原点相同,图标的transformOrigin应该设置为相对于图片原点的距离。

const labelTransformOrigin = () => {    return `${initial.width / 2 - Number(imgInfo.lableLeft) * imgScaleRateX}px ${
        initial.height / 2 - Number(imgInfo.lableTop) * imgScaleRateY
    }px`;
}

react如何实现缩放

整体代码示例:

const imgInfo = {
  lableLeft: "1900",
  lableTop: "2000",
}

const WIDTH = 1200;
const HEIGHT = 900;
const SCALE = 0.2;

const DynamicStyle= () => {

  const imgRef = React.createRef<HTMLImageElement>();
  /** 初始化缩放比例,默认为1 */
  const [rate, setRate] = useState(1);
  /** 图片样式 */
  const [imgStyle, setImgStyle] = useState<React.CSSProperties>({});
  /** 记录鼠标是否按下 */
  const [mouseDowmFlag, setMouseDowmFlag] = useState(false);
  /** 记录鼠标按下的坐标 */
  const [mouseDowmPos, setMouseDowmPos] = useState<{x: number, y: number}>({x: 0, y: 0})
  /** 图片原始大小,默认设置为1是防止计算图片原始大小与初始大小比例出现无穷大 */
  const [natural, setNatural] = useState<{width: number, height: number}>({width: 1, height: 1});
  /** 图片现在大小 */
  const [initial, setInitial] = useState<{width: number, height: number}>({width: WIDTH, height: HEIGHT});

  useEffect(() => {
    const { naturalWidth, naturalHeight, width, height } = imgRef.current as HTMLImageElement;
    setNatural({ width: naturalWidth, height: naturalHeight });
    setInitial({ width, height });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  useEffect(() => {
    document.onmouseover = () => {
      if (mouseDowmFlag) {
        setMouseDowmFlag(false);
      }
    };
    return () => {
      document.onmouseover = null;
    };
  }, [mouseDowmFlag])

  /** 缩放 */
  const handleWheelImage = (event: React.WheelEvent<HTMLImageElement>) => {
    // 向上为负,向下为正
    const bigger = event.deltaY > 0 ? -1 : 1;
    // transform偏移量
    const transformX = -initial.width / 2;
    const transformY = -initial.height / 2;
    if (bigger > 0 && rate < 2) {
      const enlargeRate = rate + SCALE;
      setImgStyle({
        ...imgStyle,
        transform: `matrix(${enlargeRate}, 0, 0, ${enlargeRate}, ${transformX}, ${transformY})`, // 默认以图片中心为原点进行缩放
      });
      setRate(enlargeRate);
    } else if (bigger < 0 && rate > 1) {
      const shrinkRate = rate - SCALE;
      setImgStyle({
        ...imgStyle,
        transform: `matrix(${shrinkRate}, 0, 0, ${shrinkRate}, ${transformX}, ${transformY})`,
      });
      setRate(shrinkRate);
    }
  }

  /** 平移 */
  const handleMouseDown = (event: React.MouseEvent<HTMLImageElement>) => {
    const { clientX, clientY } = event;
    event.stopPropagation();
    event.preventDefault(); // 阻止浏览器默认行为,拖动会打开图片
    setMouseDowmFlag(true); // 控制只有在鼠标按下后才会执行mousemove
    setMouseDowmPos({
      x: clientX,
      y: clientY,
    });
  };

  const handleMouseMove = (event: React.MouseEvent<HTMLImageElement>) => {
    event.stopPropagation();
    event.preventDefault();
    const { clientX, clientY } = event;
    const diffX = clientX - mouseDowmPos.x;
    const diffY = clientY - mouseDowmPos.y;
    if (!mouseDowmFlag || (diffX === 0 && diffY === 0)) return;
    const { offsetLeft, offsetTop } = imgRef.current as HTMLImageElement;
    const offsetX = parseInt(`${diffX + offsetLeft}`, 10);
    const offsetY = parseInt(`${diffY + offsetTop}`, 10);

    setMouseDowmPos({
      x: clientX,
      y: clientY,
    });
    setImgStyle({
      ...imgStyle,
      left: offsetX,
      top: offsetY,
    });
  };

  const handleMouseUp = (event: React.MouseEvent<HTMLImageElement>) => {
    event.stopPropagation();
    event.preventDefault();
    setMouseDowmFlag(false);
  };

  // 初始图片缩放比例(图片有原始的图片大小)
  const imgScaleRateX = initial.width / natural.width;
  const imgScaleRateY = initial.height / natural.height;

  const labelTransformOrigin = () => {
    return `${initial.width / 2 - Number(imgInfo.lableLeft) * imgScaleRateX}px ${
      initial.height / 2 - Number(imgInfo.lableTop) * imgScaleRateY
    }px`;
  }

  /** 图标位置计算 */
  const labelStyle = (): React.CSSProperties => {
    const transformX = -initial.width / 2;
    const transformY = -initial.height / 2;
    // 图标相对父元素坐标 = 图标初始位置坐标 + 平移量
    const labelLeft = parseInt(`${imgInfo.lableLeft}`, 10) * imgScaleRateX + Number(imgStyle.left || WIDTH / 2);
    const labelTop = parseInt(`${imgInfo.lableTop}`, 10) * imgScaleRateY + Number(imgStyle.top || HEIGHT / 2);
    return {
      left: labelLeft,
      top: labelTop,
      transformOrigin: labelTransformOrigin(),
      transform: `matrix(${rate}, 0, 0, ${rate}, ${transformX}, ${transformY})`,
    }
  }


  return (
    <div className={styles.imgArea}>
      <img 
        src={mapImg} 
        alt='part' 
        height={HEIGHT} 
        style={imgStyle}
        ref={imgRef}
        onWheel={handleWheelImage}
        onMouseDown={handleMouseDown}
        onMouseMove={handleMouseMove}
        onMouseUp={handleMouseUp}
      >
      </img>
      <span className={styles.label} style={labelStyle()}></span>
    </div>
  )
}

感谢各位的阅读,以上就是“react如何实现缩放”的内容了,经过本文的学习后,相信大家对react如何实现缩放这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

推荐阅读:
  1. 如何通过欺骗性的React元素实现XSS
  2. React项目的打包与部署方法

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

react

上一篇:CSS的padding属性如何使用

下一篇:react classnames怎么使用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》