我的反应成分:
import React, { PropTypes, Component } from 'react'
class Content extends Component {
handleClick(e) {
console.log("Hellooww world")
}
render() {
return (
<div className="body-content">
<div className="add-media" onClick={this.handleClick.bind(this)}>
<i className="plus icon"></i>
<input type="file" id="file" style={{display: "none"}}/>
</div>
</div>
)
}
}
export default Content
当我点击带有图标的div时,我想打开一个<input>
文件,显示我选择照片的选项。选择照片后,我想获取选择照片的值。我怎么能这样做?
答案 0 :(得分:20)
将ref属性添加到您的输入中:
<input type="file" id="file" ref="fileUploader" style={{display: "none"}}/>
更改handleClick功能:
handleClick(e) {
this.refs.fileUploader.click();
}
由于您使用的是ES6,因此需要将其绑定到handleClick函数,我们可以在构造函数中执行此操作:
constructor (props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
答案 1 :(得分:9)
其他只是将输入放在您的视图上,您将需要处理输入内容的更改。为此,请实现onChange,并获取打开的文件信息,如下所示:
<input id="myInput"
type="file"
ref={(ref) => this.upload = ref}
style={{display: 'none'}}
onChange={this.onChangeFile.bind(this)}
/>
<RaisedButton
label="Open File"
primary={false}
onClick={()=>{this.upload.click()}}
/>
onChangeFile(event) {
event.stopPropagation();
event.preventDefault();
var file = event.target.files[0];
console.log(file);
this.setState({file}); /// if you want to upload latter
}
控制台将输出:
File {
name: "my-super-excel-file.vcs",
lastModified: 1503267699000,
lastModifiedDate: Sun Aug 20 2017 19:21:39 GMT-0300 (-03),
webkitRelativePath: "",
size: 54170,
type:"application/vnd.vcs"
}
现在你可以像你想的那样使用它。但是,如果你想上传它,你必须从:
开始var form = new FormData();
form.append('file', this.state.file);
YourAjaxLib.doUpload('/yourEndpoint/',form).then(result=> console.log(result));
答案 2 :(得分:5)
React 16.3使用React.createRef()方法提供了更好的方法。见https://reactjs.org/blog/2018/03/29/react-v-16-3.html#createref-api
打字稿示例:
export class MainMenu extends React.Component<MainMenuProps, {}> {
private readonly inputOpenFileRef : RefObject<HTMLInputElement>
constructor() {
super({})
this.inputOpenFileRef = React.createRef()
}
showOpenFileDlg = () => {
this.inputOpenFileRef.current.click()
}
render() {
return (
<div>
<input ref={this.inputOpenFileRef} type="file" style={{display:"none"}}/>
<button onClick={this.showOpenFileDlg}>Open</Button>
</div>
)
}
}
答案 3 :(得分:3)
所有建议的答案都很棒。我超越并允许用户添加图像并立即预览。我使用了 React 钩子。
感谢大家的支持
结果应如下所示import React, { useEffect, useRef, useState } from 'react';
// Specify camera icon to replace button text
import camera from '../../../assets/images/camera.svg'; // replace it with your path
// Specify your default image
import defaultUser from '../../../assets/images/defaultUser.svg'; // replace it with your path
// Profile upload helper
const HandleImageUpload = () => {
// we are referencing the file input
const imageRef = useRef();
// Specify the default image
const [defaultUserImage, setDefaultUserImage] = useState(defaultUser);
// On each file selection update the default image
const [selectedFile, setSelectedFile] = useState();
// On click on camera icon open the dialog
const showOpenFileDialog = () => {
imageRef.current.click();
};
// On each change let user have access to a selected file
const handleChange = (event) => {
const file = event.target.files[0];
setSelectedFile(file);
};
// Clean up the selection to avoid memory leak
useEffect(() => {
if (selectedFile) {
const objectURL = URL.createObjectURL(selectedFile);
setDefaultUserImage(objectURL);
return () => URL.revokeObjectURL(objectURL);
}
}, [selectedFile]);
return {
imageRef,
defaultUserImage,
showOpenFileDialog,
handleChange,
};
};
// Image component
export const ItemImage = (props) => {
const {itemImage, itemImageAlt} = props;
return (
<>
<img
src={itemImage}
alt={itemImageAlt}
className="item-image"
/>
</>
);
};
// Button with icon component
export const CommonClickButtonIcon = (props) => {
const {
onHandleSubmitForm, iconImageValue, altImg,
} = props;
return (
<div className="common-button">
<button
type="button"
onClick={onHandleSubmitForm}
className="button-image"
>
<img
src={iconImageValue}
alt={altImg}
className="image-button-img"
/>
</button>
</div>
);
};
export const MainProfileForm = () => {
const {
defaultUserImage,
handleChange,
imageRef,
showOpenFileDialog,
} = HandleImageUpload();
return (
<div className="edit-profile-container">
<div className="edit-profile-image">
<ItemImage
itemImage={defaultUserImage}
itemImageAlt="user profile picture"
/>
<CommonClickButtonIcon // Notice I omitted the text instead used icon
onHandleSubmitForm={showOpenFileDialog}
iconImageValue={camera}
altImg="Upload image icon"
/>
<input
ref={imageRef}
type="file"
style={{ display: 'none' }}
accept="image/*"
onChange={handleChange}
/>
</div>
</div>
);
};
.edit-profile-container {
position: relative;
}
.edit-profile-container .edit-profile-image {
position: relative;
width: 200px;
display: flex;
justify-content: center;
}
.edit-profile-container .edit-profile-image .item-image {
height: 160px;
width: 160px;
border-radius: 360px;
}
.edit-profile-container .edit-profile-image .common-button {
position: absolute;
right: 0;
top: 30px;
}
.edit-profile-container .edit-profile-image .common-button .button-image {
outline: none;
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border: none;
background: transparent;
}
.edit-profile-container .edit-profile-image .common-button .image-button-img {
height: 30px;
width: 30px;
box-shadow: 0 10px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
}
答案 4 :(得分:2)
使用反应钩
上传新答案首先创建您的Input ref钩子
const inputFile = useRef(null)
然后将其设置为INPUT并添加要显示的样式:输入内容将不会在屏幕上显示
<input type='file' id='file' ref={inputFile} style={{display: 'none'}}/>
然后创建用于处理打开文件的函数,该函数应位于与 useRef Hook
相同的函数中 const onButtonClick = () => {
// `current` points to the mounted file input element
inputFile.current.click();
};
然后将功能设置为Button元素
<button onClick={onButtonClick}>Open file upload window</button>
答案 5 :(得分:2)
您可以将其包装在标签中,当您单击标签时,它会单击对话框。
<div>
<label htmlFor="fileUpload">
<div>
<h3>Open</h3>
<p>Other stuff in here</p>
</div>
</label>
<input hidden id="fileUpload" type="file" accept="video/*" />
</div>
答案 6 :(得分:1)
如果你可以使用钩子,这个包将解决你的问题,而无需创建输入元素。这个包不呈现任何 html 输入元素。您可以简单地在 div 元素上添加 OnClick。
这是工作演示:https://codesandbox.io/s/admiring-hellman-g7p91?file=/src/App.js
import { useFilePicker } from "use-file-picker";
import React from "react";
export default function App() {
const [files, errors, openFileSelector] = useFilePicker({
multiple: true,
accept: ".ics,.pdf"
});
if (errors.length > 0) return <p>Error!</p>;
return (
<div>
<div
style={{ width: 200, height: 200, background: "red" }}
onClick={() => openFileSelector()}
>
Reopen file selector
</div>
<pre>{JSON.stringify(files)}</pre>
</div>
);
}
调用 openFileSelector() 打开浏览器文件选择器。
文件属性:
lastModified: number;
name: string;
content: string;
https://www.npmjs.com/package/use-file-picker
我创建这个包是为了解决同样的问题。
答案 7 :(得分:0)
import React, { useRef, useState } from 'react'
...
const inputRef = useRef()
....
function chooseFile() {
const { current } = inputRef
(current || { click: () => {}}).click()
}
...
<input
onChange={e => {
setFile(e.target.files)
}}
id="select-file"
type="file"
ref={inputRef}
/>
<Button onClick={chooseFile} shadow icon="/upload.svg">
Choose file
</Button>
答案 8 :(得分:0)
我最近想用 Material UI 实现一个类似的功能,这种方法类似于 @Niyongabo 的实现,只是我使用的是 Material UI 框架并利用了 Avatar/Badge 组件。
在使用图像之前,我还调整了图像的大小。
import React, { useEffect, useRef } from "react";
import List from "@material-ui/core/List";
import t from "prop-types";
import { makeStyles } from "@material-ui/core/styles";
import { Avatar, Badge } from "@material-ui/core";
import withStyles from "@material-ui/core/styles/withStyles";
import IconButton from "@material-ui/core/IconButton";
import EditIcon from "@material-ui/icons/Edit";
import useTheme from "@material-ui/core/styles/useTheme";
import("screw-filereader");
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
"& > *": {
margin: theme.spacing(1)
}
},
form: {
display: "flex",
flexDirection: "column",
margin: "auto",
width: "fit-content"
},
input: {
fontSize: 15
},
large: {
width: theme.spacing(25),
height: theme.spacing(25),
border: `4px solid ${theme.palette.primary.main}`
}
}));
const EditIconButton = withStyles((theme) => ({
root: {
width: 22,
height: 22,
padding: 15,
border: `2px solid ${theme.palette.primary.main}`
}
}))(IconButton);
export const AvatarPicker = (props) => {
const [file, setFile] = React.useState("");
const theme = useTheme();
const classes = useStyles();
const imageRef = useRef();
const { handleChangeImage, avatarImage } = props;
useEffect(() => {
if (!file && avatarImage) {
setFile(URL.createObjectURL(avatarImage));
}
return () => {
if (file) URL.revokeObjectURL(file);
};
}, [file, avatarImage]);
const renderImage = (fileObject) => {
fileObject.image().then((img) => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const maxWidth = 256;
const maxHeight = 256;
const ratio = Math.min(maxWidth / img.width, maxHeight / img.height);
const width = (img.width * ratio + 0.5) | 0;
const height = (img.height * ratio + 0.5) | 0;
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
canvas.toBlob((blob) => {
const resizedFile = new File([blob], file.name, fileObject);
setFile(URL.createObjectURL(resizedFile));
handleChangeImage(resizedFile);
});
});
};
const showOpenFileDialog = () => {
imageRef.current.click();
};
const handleChange = (event) => {
const fileObject = event.target.files[0];
if (!fileObject) return;
renderImage(fileObject);
};
return (
<List data-testid={"image-upload"}>
<div
style={{
display: "flex",
justifyContent: "center",
margin: "20px 10px"
}}
>
<div className={classes.root}>
<Badge
overlap="circle"
anchorOrigin={{
vertical: "bottom",
horizontal: "right"
}}
badgeContent={
<EditIconButton
onClick={showOpenFileDialog}
style={{ background: theme.palette.primary.main }}
>
<EditIcon />
</EditIconButton>
}
>
<Avatar alt={"avatar"} src={file} className={classes.large} />
</Badge>
<input
ref={imageRef}
type="file"
style={{ display: "none" }}
accept="image/*"
onChange={handleChange}
/>
</div>
</div>
</List>
);
};
AvatarPicker.propTypes = {
handleChangeImage: t.func.isRequired,
avatarImage: t.object
};
export default AvatarPicker;