效果图:
// 新建index.js文件,img就是url地址
<ImageMagnifier minImg={img} maxImg={img} width={250} height={250} />
// 新建ImageMagnifier.js文件
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import girdImg from 'public/images/gird.png';
class ImageMagnifier extends Component {
constructor(props) {
super(props);
this.state = {
params: {
// 放大倍数
scale: 2,
// 组件宽
width: props.width,
height: props.height
},
// 略缩图
minImg: '',
// 大图
maxImg: '',
// 开关
magnifierOff: false,
// 图片加载情况
imgLoad: false,
cssStyle: {
// 图片容器
imgContainer: {
width: '400px',
height: '400px',
cursor: 'move',
position: 'relative'
},
// 鼠标悬停小方块
mouseBlock: {
position: 'absolute',
top: '0',
left: '0',
width: '100px',
height: '100px',
backgroundImage: `url(${girdImg})`,
backgroundAttachment: 'scroll',
backgroundRepeat: 'repeat',
backgroundPosition: '0 0',
zIndex: 99
},
// 鼠标悬停遮罩层
maskBlock: {
position: 'absolute',
top: '0',
left: '0',
width: '100%',
height: '100%',
background: 'rgba(0,0,0,0)',
zIndex: 100
},
// 放大镜
magnifierContainer: {
position: 'absolute',
left: '480px',
top: '50px',
width: '600px',
height: '600px',
overflow: 'hidden',
zIndex: 98
},
// 图片
imgStyle: {
width: '100%',
height: '100%'
},
// scale 放大的只是图片初始的宽高
imgStyle2: {
width: '400px',
height: '400px',
position: 'absolute',
top: 0,
left: 0,
transform: 'scale(4)',
transformOrigin: 'top left'
}
}
};
}
// 初始化
componentWillMount() {
this.initParam();
this.updataImg(this.props);
}
// props 变化时更新
componentWillReceiveProps(nextProps) {
this.updataImg(nextProps);
}
// 鼠标移入
mouseEnter = () => {
this.setState({
magnifierOff: true
});
};
// mouse remove
mouseLeave = () => {
this.setState({
magnifierOff: false
});
}
// mouse move
mouseMove = event => {
let e = event.nativeEvent;
const { offsetX, offsetY } = e;
this.calculationBlock(offsetX, offsetY);
}
// calculation params
calculationBlock(offsetx, offsety) {
let cssStyle = JSON.parse(JSON.stringify(this.state.cssStyle));
let mouseOffSetX = offsetx - 50; // mouseOffSetX = offset - maskWidth / 2 mask 位置
let mouseOffSetY = offsety - 50; // mouseOffSetX = offset - maskHeight / 2 mask 位置
// 兼容鼠标移动过快导致计算失误,只要小于或大于对应值,直接设置偏移量等于最小或最大值
if (mouseOffSetX < 0) {
mouseOffSetX = 0;
}
// mask 移动在图片内 参数可根据 clientWidth、clientHeight 计算
if (mouseOffSetX > 150) {
mouseOffSetX = 150;
}
if (mouseOffSetY < 0) {
mouseOffSetY = 0;
}
if (mouseOffSetY > 150) {
mouseOffSetY = 150;
}
// 移动 mask 距离
cssStyle.mouseBlock.left = parseFloat(mouseOffSetX) + 'px';
cssStyle.mouseBlock.top = parseFloat(mouseOffSetY) + 'px';
// 右侧大图片,等比例移动
// 大图片移动的距离 / mask 移动的距离 = 大图片 / 小图片
let bigImg = document.querySelector('.big img');
let smallImg = document.querySelector('.small img');
let ratio = bigImg.offsetWidth / smallImg.offsetWidth;
cssStyle.imgStyle2.left = -parseFloat((mouseOffSetX) * ratio) + 'px';
cssStyle.imgStyle2.top = -parseFloat((mouseOffSetY) * ratio) + 'px';
this.setState({
cssStyle: cssStyle
});
}
// 初始化参数
initParam() {
let cssStyle = JSON.parse(JSON.stringify(this.state.cssStyle));
let params = JSON.parse(JSON.stringify(this.state.params));
cssStyle.imgContainer.width = params.width + 'px';
cssStyle.imgContainer.height = params.height + 'px';
cssStyle.imgStyle2.width = params.width + 'px';
cssStyle.imgStyle2.height = params.height + 'px';
cssStyle.imgStyle2.transform = 'scale(' + params.scale + ')';
this.setState({
cssStyle: cssStyle
});
}
// 更新图片
updataImg(props) {
this.setState({
minImg: props.minImg,
maxImg: props.maxImg
});
}
// 图片加载情况
handleImageLoaded(e) {
this.setState({ imgLoad: true });
}
// 图片加载中
handleImageErrored() {
this.setState({
imgLoad: false
});
}
render() {
const { cssStyle, magnifierOff, minImg, maxImg, imgLoad } = this.state;
return (
<div className={'box'}>
<div className={'small'} style={cssStyle.imgContainer}>
{/* 加载小图 */}
<img
className={'small img'}
style={cssStyle.imgStyle} src={minImg} alt={''} />
<div
className={'mask'}
style={cssStyle.maskBlock}
onMouseEnter={this.mouseEnter}
onMouseLeave={this.mouseLeave}
onMouseMove={this.mouseMove} />
{magnifierOff && <div style={cssStyle.mouseBlock} />}
</div>
{magnifierOff && (
<div className={'big hide'}
style={cssStyle.magnifierContainer}>
<img
className={'big img'}
style={cssStyle.imgStyle2}
src={maxImg}
onLoad={this.handleImageLoaded.bind(this)}
onError={this.handleImageErrored.bind(this)}
alt={''} />
{!imgLoad && 'failed to load'}
</div>
)}
</div>
);
}
}
export default ImageMagnifier;
ImageMagnifier.propTypes = {
width: PropTypes.number,
height: PropTypes.number
};