主要是自己以后用到的时候方便找.
使用
// 引用
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;}