我正在尝试制作一个用户可以上传图像并将其发送给电子邮件的应用程序,该应用程序在除Safari之外的所有浏览器上均能正常工作。对于移动浏览器和Web浏览器,当我选择要上传的图像时,似乎没有任何预览,甚至没有加载(准备发送)。有什么我可以解决的吗?我的代码非常简单:
const EnterDetailPage = props => {
const [imageUrl, setImageUrl] = useState("");
const [imageFile, setImageFile] = useState();
const [upload, setUpload] = useState(null);
const handleUploadChange = async e => {
setLoading(true);
const file = e.target.files[0];
if (!file) {
return;
}
setUpload(URL.createObjectURL(file));
setImageFile(file);
const ref = firebase
.storage()
.ref()
.child(uuid.v4());
const snapshot = await ref.put(file);
let getImageUrl = await snapshot.ref.getDownloadURL();
setImageUrl(getImageUrl);
setLoading(false);
console.log(getImageUrl);
};
let imgPreview = null;
if (upload) {
imgPreview = (
<Avatar
variant="square"
src={upload}
alt="Avatar"
className={classes.bigAvatar}
/>
);
}
return(
<div className="m-auto p-16 sm:px-24 sm:mx-auto max-w-xl">
<input
accept="image/jpeg,image/gif,image/png"
className="hidden"
id="button-file"
type="file"
// onChange={handleUploadChange}
onInput={handleUploadChange}
onClick={event => {
event.target.value = null;
}}
/>
<label
htmlFor="button-file"
className={`${classes.bigAvatar} mt-8 bg-gray-300 m-auto flex items-center justify-center relative w-128 h-128 rounded-4 a-mr-16 a-mb-16 overflow-hidden cursor-pointer shadow-1 hover:shadow-xl`}
>
<div className="absolute flex items-center justify-center w-full h-full z-50">
{imageUrl ? null :
<Icon fontSize="large" color="primary" className="cloud-icon">
cloud_upload
</Icon>}
</div>
{imgPreview}
</label>
);
}:
我将代码与本文的代码进行了比较:https://w3path.com/react-image-upload-or-file-upload-with-preview/
似乎我已经做了完全相同的事情...为什么我没有得到相同的结果?
input
事件侦听器的onInput
元素-回调从未执行。相反,您可以使用onChange
事件侦听器。对于下面的示例,我通过设置带有超时的Promise
来伪造API调用,但这不是必需的,仅用于演示目的。另外,我喜欢在多个单独的状态上使用对象,尤其是在状态需要同步的情况下-它更干净,更易于阅读,并且功能更像基于class
的组件。
来源:
import React, { useRef, useState } from "react";
import { CircularProgress, Icon, Fab } from "@material-ui/core";
const initialState = {
isLoading: false,
imageName: "",
imagePreview: null,
imageSize: 0
};
const EnterDetailPage = () => {
const [state, setState] = useState(initialState);
const uploadInputEl = useRef(null);
const handleUploadChange = async ({ target: { files } }) => {
setState(prevState => ({ ...prevState, isLoading: true }));
const file = files[0];
await new Promise(res => {
setTimeout(() => {
res(
setState(prevState => ({
...prevState,
imageName: file.name,
imagePreview: URL.createObjectURL(file),
imageSize: file.size,
isLoading: false
}))
);
}, 2000);
});
};
const resetUpload = () => {
setState(initialState);
uploadInputEl.current.value = null;
};
const uploadImage = async () => {
if (state.imagePreview)
setState(prevState => ({ ...prevState, isLoading: true }));
await new Promise(res => {
setTimeout(() => {
res(alert(JSON.stringify(state, null, 4)));
resetUpload();
}, 2000);
});
};
const { imagePreview, imageName, imageSize, isLoading } = state;
return (
<div style={{ padding: 20 }}>
<div style={{ textAlign: "center" }}>
<div>
<input
accept="image/jpeg,image/gif,image/png"
className="hidden"
id="button-file"
type="file"
ref={uploadInputEl}
onChange={handleUploadChange}
/>
<label htmlFor="button-file">
<div>
{imagePreview ? (
<>
<img
src={imagePreview}
alt="Avatar"
style={{ margin: "0 auto", maxHeight: 150 }}
/>
<p style={{ margin: "10px 0" }}>
({imageName} - {(imageSize / 1024000).toFixed(2)}MB)
</p>
</>
) : (
<Icon fontSize="large" color="primary" className="cloud-icon">
cloud_upload
</Icon>
)}
</div>
</label>
<Fab
variant="extended"
size="large"
color="primary"
aria-label="add"
className=""
type="button"
onClick={uploadImage}
>
{isLoading ? (
<CircularProgress style={{ color: "white" }} />
) : (
"Submit"
)}
</Fab>
{imagePreview && (
<Fab
variant="extended"
size="large"
color="default"
aria-label="add"
className=""
type="button"
onClick={resetUpload}
>
Cancel
</Fab>
)}
</div>
</div>
</div>
);
};
export default EnterDetailPage;