当用户单击文件输入对话框上的十字图标或取消按钮时,我想要一个事件或收到通知,以便我可以基于此执行一些任务。
仅当用户单击 Open 按钮时才会触发 onChange 事件。
当用户使用 ReactJS 单击十字图标或取消按钮时,有没有办法收到通知?
下面是工作代码片段。
class Test extends React.Component {
constructor() {
super();
this.fileInputClicked = this.fileInputClicked.bind(this);
}
fileInputClicked(event){
let file = event.target.files[0];
console.log("File is Selected", file);
}
render() {
return (
<div>
<div>
<p>Hello world</p>
<input type="file" onChange={this.fileInputClicked}/>
</div>
</div>
);
}
}
ReactDOM.render(<Test/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app' />
嗯,这可能是我会做的,但我真的不喜欢它,而且我认为由于用户决定不上传文件而执行某些操作的整个想法并不是一个良好的用户体验,因此请明智地使用它。
fileInputClicked(event){
let file = event.target.files[0];
console.log("File is Selected", file);
window.removeEventListener('focus', this.handleFocusBack);
}
handleFocusBack(){
console.log('focus-back');
window.removeEventListener('focus', this.handleFocusBack);
}
clickedFileInput(){
window.addEventListener('focus', this.handleFocusBack);
}
render() {
return (
<div>
<div>
<p>Hello world</p>
<input onClick={this.clickedFileInput} type="file" onChange={this.fileInputClicked}/>
</div>
</div>
);
}
这样,当用户决定关闭文件输入时,他会重新关注窗口,您将获得所需的
handleFocusBack
功能,当他添加文件时,他会转到 fileInputClicked
。
Afaik,没有“开箱即用”的机制来实现你想要的。
这是一个老问题,但我也需要一个答案。然而,解决方案比 @Matan-Bobi 建议的稍微复杂一些。
在文件对话框打开之前会触发
click
事件。focus
事件都会在文件对话框关闭后 被触发。也就是说,它是通过单击“文件对话框”中“打开”按钮上的“”或“取消”按钮上的“”来触发的。
单击“打开”按钮之后change
事件。如果单击“取消”按钮,则永远不会触发它。因此,要检测是否单击“取消”按钮,您必须再等待
change
事件。在我的测试中,100 毫秒似乎是一个不错的等待时间。
我下面的代码提供了太多信息(特别是如果您取消注释
componentDidUpdate
方法中的行),但它允许您查看需要跳过的所有环节。
const CANCEL_DELAY = 100;
let render = 0;
class Test extends React.Component {
constructor() {
super();
this.state = {
feedback: "Browse for a file...",
filename: "",
timeOut: 0
};
this.dialogOpened = this.dialogOpened.bind(this);
this.dialogClosed = this.dialogClosed.bind(this);
this.fileSelected = this.fileSelected.bind(this);
this.cancelDialog = this.cancelDialog.bind(this);
}
dialogOpened() {
console.log("Dialog opened");
window.addEventListener('focus', this.dialogClosed, { once: true});
this.setState(() => ({ filename: "" }));
}
dialogClosed() {
console.log("Dialog closed");
console.time("closed_after");
const timeOut = setTimeout(this.cancelDialog, CANCEL_DELAY);
console.log(`timeOut ${timeOut} created`);
this.setState(() => ({
feedback: 'Dialog closed',
timeOut
}));
}
fileSelected() {
console.timeEnd("closed_after"); // <25 ms on my computer
const file = event.target.files[0];
this.setState(() => ({
feedback: `File was selected`,
filename: file.name
}));
// TODO: Do something with the selected file
console.log(`+++ File: ${file.name} selected +++`);
this.destroyTimeout();
}
cancelDialog() {
console.log(`cancelDialog triggered after ${CANCEL_DELAY} ms`);
console.timeEnd("closed_after");
this.setState(() => ({ feedback: "Dialog was cancelled" }));
// TODO: Do something about the cancellation
console.log("--- File dialog was cancelled ---");
this.destroyTimeout(); // > 103 ms
}
destroyTimeout() {
console.log(`timeout ${this.state.timeOut} destroyed (${this.state.feedback})
`);
clearTimeout(this.state.timeOut);
this.setState(() => ({ timeOut: 0 }));
}
render() {
return (
<div>
<p>{this.state.feedback}</p>
<input type="file"
onClick={this.dialogOpened}
onChange={this.fileSelected}
/>
<p>{this.state.filename}</p>
</div>
);
}
componentDidUpdate() {
// // Uncomment for more feedback
// console.log(`Update ${++render}) updated state:`, this.state);
}
}
ReactDOM.render(<Test/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app' />
一个简单的方法是验证您的文件数组是否为空。
事件.目标.文件.长度= 0
const onFileChange = (e) => { if(e.target.files.length ===0) { setFile(null); // undefined take place instead by default // the cancel event logics will always land here } else{ setResume(e.target.files[0]); } }