我正在使用以下代码动态创建画布高度。但是,即使有onLoad
,画布高度的控制台日志也为0。
index.js
import React, {useRef, useState, useEffect} from "react";
import ReactDOM from "react-dom";
import background from "./background.png";
const Canvas = (props) => {
const canvas = useRef(null);
const image = useRef(null);
const [xLoc, setxLoc] = useState()
const [yLocTop, setyLocTop] = useState()
const [yLocBottom, setyLocBottom] = useState()
const [canX, setCanX] = useState()
const [canY, setCanY] = useState()
useEffect(() => {
const ctx = canvas.current.getContext("2d");
image.current.onload = () => {
ctx.drawImage(image.current, 0, 0);
ctx.font = "20px Courier";
ctx.textAlign = "center";
ctx.fillText(props.textTop, xLoc, yLocTop);
ctx.textAlign = "center";
ctx.fillText(props.textBottom, xLoc, yLocBottom);
};
});
useEffect(() => {
const ctx = canvas.current.getContext("2d");
ctx.drawImage(image.current, 0, 0);
ctx.font = "20px Courier";
ctx.textAlign = "center";
ctx.fillText(props.textTop, xLoc, yLocTop);
ctx.textAlign = "center";
ctx.fillText(props.textBottom, xLoc, yLocBottom);
});
const handleOnLoad = e => {
console.log(e.target.offsetHeight)
setCanX(e.target.offsetWidth)
setCanY(e.target.offsetHeight)
setxLoc(canX / 2);
setyLocTop(canY * 0.87);
setyLocBottom(canY * 0.13);
};
return (
<div>
{console.log(canX)}
{/* <canvas ref={canvas} width={canX || 0} height={canY || 0} /> */}
<canvas ref={canvas} width="270" height="80" />
<img
ref={image}
src={props.background}
onLoad={handleOnLoad}
hidden/>
</div>
);
};
function App() {
return (
<div className="App">
<Canvas textTop="Top" textBottom="Bottom" background={background} />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
沙盒链接为here
答案 0 :(得分:3)
问题在于,如果您设置<img hidden/>
,则图像尺寸将仅为0高度,0宽度。
您仍然可以隐藏图像,而无需使用隐藏的道具。使用将可见性设置为隐藏的样式,图像尺寸将正确传递。如果您想将img
推到画布后面,以使其永远不会被单击。使用以下内容:
<img
ref={image}
src={props.background}
onLoad={handleOnLoad}
style={{ visibility: "hidden", position: "absolute", top: "0", zIndex: "-1" }}
alt=""
/>
请参阅沙箱:https://codesandbox.io/s/affectionate-wildflower-jov21
此外,您可以解决synchronous
函数的handleLoad()
行为。状态更新功能在执行之前不会等待其他逻辑完成。在setCanX
有时间完成之前,setxLoc
已经在运行,在这种情况下,canX
仍然是undefined
。这就是为什么当我们尝试将NaN
除以2时得到undefined
的原因。它们没有像asynchronous
那样等待。
您应该直接将event.target.offsetStuff
传递给setter函数,它将起作用
const handleOnLoad = e => {
const { offsetHeight, offsetWidth } = e.target
setCanX(offsetWidth);
setCanY(offsetHeight);
setxLoc(offsetWidth / 2);
setyLocTop(offsetHeight * 0.87);
setyLocBottom(offsetHeight * 0.13);
};
答案 1 :(得分:0)
该图像似乎有两个onload
函数,一个在useEffect()
中,另一个在图像的属性中。您实际上可以将它们组合在一起,并且效果很好。这是沙箱link。
import React, { useRef, useState, useEffect } from "react";
import ReactDOM from "react-dom";
import background from "./background.png";
const Canvas = props => {
const canvas = useRef(null);
const image = useRef(null);
const [xLoc, setxLoc] = useState();
const [yLocTop, setyLocTop] = useState();
const [yLocBottom, setyLocBottom] = useState();
const [canX, setCanX] = useState();
const [canY, setCanY] = useState();
useEffect(() => {
const ctx = canvas.current.getContext("2d");
image.current.onload = () => {
ctx.drawImage(image.current, 0, 0);
ctx.font = "20px Courier";
ctx.textAlign = "center";
ctx.fillText(props.textTop, xLoc, yLocTop);
ctx.textAlign = "center";
ctx.fillText(props.textBottom, xLoc, yLocBottom);
setCanX(image.current.width);
setCanY(image.current.height);
setxLoc(canX / 2);
setyLocTop(canY * 0.87);
setyLocBottom(canY * 0.13);
};
});
useEffect(() => {
const ctx = canvas.current.getContext("2d");
ctx.drawImage(image.current, 0, 0);
ctx.font = "20px Courier";
ctx.textAlign = "center";
ctx.fillText(props.textTop, xLoc, yLocTop);
ctx.textAlign = "center";
ctx.fillText(props.textBottom, xLoc, yLocBottom);
});
return (
<div>
<canvas ref={canvas} width={canX || 0} height={canY || 0} />
{/* <canvas ref={canvas} width="270" height="80" /> */}
<img ref={image} src={props.background} hidden />
</div>
);
};
function App() {
return (
<div className="App">
<Canvas textTop="Top" textBottom="Bottom" background={background} />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);