您好,登錄后才能下訂單哦!
這篇文章主要講解了“react如何實現縮放”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“react如何實現縮放”吧!
react實現縮放的方法:1、監聽onWheel事件;2、設置事件對象event的屬性deltaY,當向上滾動時“deltaY<0”,向下滾動時“deltay>0”;3、修改每次滾動時縮放的比例,同時更改transform樣式按比例進行縮放即可。
react圖片縮放、平移(position、transform實現)
很多網頁都會給文案附上一些圖片補充描述,例如在說到地址時,會在旁邊附上一張地圖,并且在地圖上標注該地址。如果附上的圖片很小,很難看清楚地址的具體信息,有些產品經理會給圖片設計一個可以平移、放大縮小的功能。本文將一一實現上述功能。
廢話不多說,先給上效果圖:
主要三個功能點:
圖片平移
圖片縮放
車站標注
圖片平移可以監聽這三個事件實現:onMouseDown、onMouseMove、onMouseUp
。onMouseDown
事件記錄每次鼠標按下的坐標位置;onMouseMove
事件計算出每次平移的距離,該距離加上拖動前圖片距離父元素的距離就等于拖動后圖片相對于父元素的距離;onMouseUp
事件觸發時,注銷或者不讓執行onMouseDown、onMouseMove
事件,防止只要鼠標移入圖片就會平移。
這三個事件需要阻止瀏覽器的默認行為,不然在移動時會自動打開圖片。
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
樣式按比例進行縮放。
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個參數矯正transformOrigin
,transform: matrix(${shrinkRate}, 0, 0, ${shrinkRate}, ${transformX}, ${transformY})
首先,定義一個常量表示圖標的坐標,這個坐標是相對于原始圖片左上角的定位。
const imgInfo = { lableLeft: "1900", lableTop: "2000",}
這里,解釋一下原始圖的概念:
隨便在網上查看一個圖片元素,比如上面。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);
當圖片縮放時,圖標需要隨著圖片一起縮放。如果沒有對圖標設置transformOrigin
,默認時相對圖標的中心縮放的。為了保證圖標隨著圖片一起縮放,那就必須使得圖片和圖標的縮放參照原點相同,圖標的transformOrigin
應該設置為相對于圖片原點的距離。
const labelTransformOrigin = () => { return `${initial.width / 2 - Number(imgInfo.lableLeft) * imgScaleRateX}px ${
initial.height / 2 - Number(imgInfo.lableTop) * imgScaleRateY
}px`;
}
整體代碼示例:
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如何實現縮放這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。