React实现图片缩放效果

本文介绍了如何在React应用中实现图片的缩放效果,通过利用React组件化思想和CSS样式技巧,详细讲解了从点击按钮到图片平滑缩放的完整过程,包括关键代码实现和效果展示。
摘要由CSDN通过智能技术生成
import React, {
    PureComponent, createRef } from 'react'
import PropTypes from 'prop-types'

// interface POSIF {
   
//   posX: number;
//   posY: number;
// }
// interface IProps {
   
//   // children: PropTypes.node.isRequired,
//   className ?: string;
//   style?: React.CSSProperties;
//   minZoom?: number;
//   maxZoom?: number;
//   scrollVelocity?: number;
//   onZoomChange?: (pos: POSIF) => void;
//   onPanChange?: (pos: POSIF) => void;
//   animDuration?: number;
//   doubleTouchMaxDelay?: number;
//   decelerationDuration?: number;
// }
// interface IState {
   
//   zoom: number;
//   posX: number;
//   posY: number;
//   cursor: string;
//   transitionDuration: number;
// }
export default class PrismaZoom extends PureComponent {
   
  static propTypes = {
   
    children: PropTypes.node.isRequired,
    className: PropTypes.string,
    style: PropTypes.object,
    minZoom: PropTypes.number,
    maxZoom: PropTypes.number,
    scrollVelocity: PropTypes.number,
    onZoomChange: PropTypes.func,
    onPanChange: PropTypes.func,
    animDuration: PropTypes.number,
    doubleTouchMaxDelay: PropTypes.number,
    decelerationDuration: PropTypes.number
  }

  static defaultProps = {
   
    // Class name to apply on the zoom wrapper
    className: null,
    // Style to apply on the zoom wrapper
    style: {
   },
    // Minimum zoom ratio
    minZoom: 1,
    // Maximum zoom ratio
    maxZoom: 5,
    // Zoom increment or decrement on each scroll wheel detection
    scrollVelocity: 0.2,
    // Function called each time the zoom value changes
    onZoomChange: null,
    // Function called each time the posX or posY value changes (aka images was panned)
    onPanChange: null,
    // Animation duration (in seconds)
    animDuration: 0.25,
    // Max delay between two taps to consider a double tap (in milliseconds)
    doubleTouchMaxDelay: 300,
    // Decelerating movement duration after a mouse up or a touch end event (in milliseconds)
    decelerationDuration: 750
  }

  static defaultState = {
   
    // Transform scale value property
    zoom: 1,
    // Transform translateX value property
    posX: 0,
    // Transform translateY value property
    posY: 0,
    // Cursor style property
    cursor: 'auto'
  }

  constructor (props) {
   
    super(props)
    // Reference to the main element
    this.ref = createRef()
    // Last cursor position
    this.lastCursor = null
    // Last touch position
    this.lastTouch = null
    // Last touch time in milliseconds
    this.lastTouchTime = 0
    // Last double tap time (used to limit multiple double tap) in milliseconds
    this.lastDoubleTapTime = 0
    // Last calculated distance between two fingers in pixels
    this.lastTouchDistance = null
    // Last request animation frame identifier
    this.lastRequestAnimationId = null

    this.state = {
   
      ...this.constructor.defaultState,
      transitionDuration: props.animDuration
    }
  }

  /**
   * Calculates new translate positions for CSS transformations.
   * @param  {Number} x     Relative (rect-based) X position in pixels
   * @param  {Number} y     Relative (rect-based) Y position in pixels
   * @param  {Number} zoom  Scale value
   * @return {Array}        New X and Y positions
   */
  getNewPosition = (x, y, zoom) => {
   
    const [prevZoom, prevPosX, prevPosY] = [this.state.zoom, this.state.posX, this.state.posY]

    if (zoom === 1) {
   
      return [0, 0]
    }

    if (zoom > prevZoom) {
   
      // Get container coordinates
      const rect = this.ref.current.getBoundingClientRect()

      // Retrieve rectangle dimensions and mouse position
      const [centerX, centerY] = [rect.width / 2, rect.height / 2]
      const [relativeX, relativeY] = [x - rect.left - window.pageXOffset, y - rect.top - window.pageYOffset]

      // If we are zooming down, we must try to center to mouse position
      const [absX, absY] = [(centerX - relativeX) / prevZoom, (centerY - relativeY) / prevZoom]
      const ratio = zoom - prevZoom
      return [
        prevPosX + (absX * ratio),
        prevPosY + (absY * ratio)
      ]
    } else {
   
      // If we are zooming down, we shall re-center the element
      return [
        (prevPosX * (zoom - 1)) / (prevZoom - 1),
        (prevPosY * (zoom - 1)) / (prevZoom - 1)
      ]
    }
  }

  /**
   * Calculates the narrowed shift for panning actions.
   * @param  {Number} shift      Initial shift in pixels
   * @param  {Number} minLimit   Minimum limit (left or top) in pixels
   * @param  {Number} maxLimit   Maximum limit (right or bottom) in pixels
   * @param  {Number} minElement Left or top element position in pixels
   * @param  {Number} maxElement Right or bottom element position in pixels
   * @return {Number}            Narrowed shift
   */
  getLimitedShift = (shift, minLimit, maxLimit, minElement, maxElement) => {
   
    if (shift > 0) {
   
      if (minElement > minLimit) {
   
        // Forbid move if we are moving to left or top while we are already out minimum boudaries
        return 0
      } else if (minElement + shift > minLimit) {
   
        // Lower the shift if we are going out boundaries
        return minLimit - minElement
      }
    } else if (shift < 0) {
   
      if (maxElement 
React 放大镜效果通常是指在前端开发中使用 React 技术实现的一种交互式功能,让用户能够放大图片或者内容区域。这个效果通常是通过 CSS 的 `transform: scale()` 属性结合组件的状态或 props 来实现的。当你点击某个区域或者触发某些事件时,会改变元素的缩放比例,提供类似看图软件中的放大效果。 以下是实现简单放大镜效果的一个基本步骤: 1. 创建一个 React 组件,包含一个原图容器和一个可放大显示的子元素(如 `<img>` 或 `<div>`)。 2. 给原图添加样式,设置初始缩放比例为 1。 3. 定义一个状态变量来存储当前的缩放比例,初始化为 1(非放大)。 4. 添加事件处理函数,在用户触发事件(如鼠标移动、双击等)时更新缩放比例。 5. 使用 `style` 属性动态设置子元素的 `scale` 样式,实现放大效果。 下面是一个简单的示例代码: ```jsx import React, { useState } from 'react'; const ZoomableImage = ({ src }) => { const [zoom, setZoom] = useState(1); const handleMouseEnter = () => setZoom(1.05); const handleMouseLeave = () => setZoom(1); const handleClick = () => setZoom(zoom > 1 ? 1 : zoom + 0.1); // 鼠标单击放大 return ( <div onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}> <img src={src} style={{ transform: `scale(${zoom})`, transition: 'transform 0.3s' }} /> <button onClick={handleClick}>放大</button> </div> ); }; export default ZoomableImage; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值