实现图片的缩放和拖拽

69 阅读1分钟

 主要是自己以后用到的时候方便找.

是从juejin.cn/post/700989…

使用

// 引用
import ZoomImg from "@/components/ZoomImg";
// 使用 id传入是因为dom的id重名会有bug url就是图片的路径
<ZoomImg id={"1"} url={"/images/1.png"} />

定义

import React, { useEffect } from "react";
import style from "./style.module.less";
const ZoomImg = (props) => {  
    let result,    
    x,    
    y,    
    scale = 1,    
    minScale = 0.5,    
    maxScale = 4,    
    isPointerdown = false, 
    // 按下标识    
    point = { x: 0, y: 0 }, 
    // 第一个点坐标    
    diff = { x: 0, y: 0 }, 
    // 相对于上一次pointermove移动差值    
    lastPointermove = { x: 0, y: 0 }; 
    // 用于计算diff  
    function getImgSize(naturalWidth, naturalHeight, maxWidth, maxHeight) {    
        const imgRatio = naturalWidth / naturalHeight;    
        const maxRatio = maxWidth / maxHeight;    
        let width, height;    
        // 如果图片实际宽高比例 >= 显示宽高比例    
        if (imgRatio >= maxRatio) {      
            if (naturalWidth > maxWidth) {        
                // 实际宽度比最大宽度大        
                width = maxWidth;        
                height = (maxWidth / naturalWidth) * naturalHeight;      
            } else {        
                // 实际宽度比较小        
                width = naturalWidth;        
                height = naturalHeight;      
            }    
        } else {      
            // 如果图片宽高比例 < 显示宽高比例      
            if (naturalHeight > maxHeight) {        
                // 实际高度大于显示高度        
                width = (maxHeight / naturalHeight) * naturalWidth;        
                height = maxHeight;      
            } else {        
                // 实际高度小于显示高度        
                width = naturalWidth;        
                height = naturalHeight;      
            }    
        }    
        return { width: width, height: height };  
    }  
    // 拖拽查看  
    function drag() {    
        const image = document.getElementById(`image_${props.id}`);
        // 绑定 pointerdown    
        image.addEventListener("pointerdown", function (e) {      
            isPointerdown = true;      
            image.setPointerCapture(e.pointerId);      
            point = { x: e.clientX, y: e.clientY };      
            lastPointermove = { x: e.clientX, y: e.clientY };    
        });    
        // 绑定 pointermove    
        image.addEventListener("pointermove", function (e) {      
            if (isPointerdown) {        
                const current1 = { x: e.clientX, y: e.clientY };        
                diff.x = current1.x - lastPointermove.x;        
                diff.y = current1.y - lastPointermove.y;        
                lastPointermove = { x: current1.x, y: current1.y };        
                x += diff.x;        
                y += diff.y;        
                image.style.transform = "translate3d(" + x + "px, " + y + "px, 0) scale(" + scale + ")";
           }     
            e.preventDefault();    
        });    
        // 绑定 pointerup    
        image.addEventListener("pointerup", function (e) {      
            if (isPointerdown) {        
                isPointerdown = false;      
            }    
        });    
        // 绑定 pointercancel    
        image.addEventListener("pointercancel", function (e) {      
            if (isPointerdown) {        
                isPointerdown = false;      
            }    
        });  
}  
// 滚轮缩放  
function wheelZoom() {    
    const container = document.getElementById(`container_${props.id}`);    
    const image = document.getElementById(`image_${props.id}`);    
    container.addEventListener("wheel", function (e) {      
        let ratio = 1.1;      
        // 缩小      
        if (e.deltaY > 0) {        
            ratio = 1 / 1.1;      
        }      
        // 限制缩放倍数      
        const _scale = scale * ratio;      
        if (_scale > maxScale) {        
            ratio = maxScale / scale;        
            scale = maxScale;      
        } else if (_scale < minScale) {        
            ratio = minScale / scale;        
            scale = minScale;      
        } else {        
            scale = _scale;      
        }      
        // 目标元素是img说明鼠标在img上,以鼠标位置为缩放中心,否则默认以图片中心点为缩放中心      
        if (e.target.tagName === "IMG") {        
            const origin = {          
                x: (ratio - 1) * result.width * 0.5,          
                y: (ratio - 1) * result.height * 0.5,        
            };        
            // 计算偏移量        
            x -= (ratio - 1) * (e.clientX - x) - origin.x;        
            y -= (ratio - 1) * (e.clientY - y) - origin.y;      
        }      
        image.style.transform ="translate3d(" + x + "px, " + y + "px, 0) scale(" + scale + ")";
        e.preventDefault();    
    });  
}  
// 中间图片的拖拉和缩放的初始化和方法调用  
useEffect(() => {    
    const image = document.getElementById(`image_${props.id}`);    
    const container = document.getElementById(`container_${props.id}`);    
    console.log(image.naturalWidth, image.naturalHeight);    
    console.log(container.clientWidth, container.clientHeight);    
    image.addEventListener("load", function () {      
        // 根据图片和容器的宽高返回一个合适的宽高值      
        result = getImgSize(image.naturalWidth,image.naturalHeight,container.clientWidth,container.clientHeight);
        // 控制长宽      
        image.style.width = result.width + "px";      
        image.style.height = result.height + "px";      
        // 控制位置      
        x = (container.clientWidth - result.width) * 0.5;      
        y = (container.clientHeight - result.height) * 0.5;      
        image.style.transform = "translate3d(" + x + "px, " + y + "px, 0) scale(1)";      
        // 拖拽查看      
        drag();      
        // 滚轮缩放      
        wheelZoom();    
    });  
});  
    return (    
        <div id={`container_${props.id}`} className={style.container}>      
            <img id={`image_${props.id}`} src={props.url} className={style.model} />    
        </div>  );
    };
export default ZoomImg;

css

.container {  position: relative;  width: 100%;  height: 100%;  overflow: hidden;}.model {  height: 100%;  width: 100%;  max-width: 100%;  min-width: 100%;  animation-name: light;  animation-duration: 2s;  animation-timing-function: linear;  animation-iteration-count: infinite;  animation-direction: alternate;  opacity: 0.9;}