Javascript 以编程方式生成/激活的文件输入不';不要总是触发'input'事件

Javascript 以编程方式生成/激活的文件输入不';不要总是触发'input'事件,javascript,html,google-chrome,browser,blink,Javascript,Html,Google Chrome,Browser,Blink,我的web应用程序上有一个按钮,在单击事件处理程序中有以下代码: const fileInputEl = document.createElement('input'); fileInputEl.type = 'file'; fileInputEl.accept = 'image/*'; fileInputEl.addEventListener('input', (e) => { if (!e.target.files.length) { return; } //

我的web应用程序上有一个按钮,在单击事件处理程序中有以下代码:

const fileInputEl = document.createElement('input');
fileInputEl.type = 'file';
fileInputEl.accept = 'image/*';

fileInputEl.addEventListener('input', (e) => {
  if (!e.target.files.length) {
    return;
  }

  // Handle files here...
});  

fileInputEl.dispatchEvent(new MouseEvent('click'));
有时(大约8个中的1个),在选择文件后,
input
事件在选择文件后不会触发。我猜这是元素生命周期中的一个浏览器错误

除了将元素附加到页面并在以后将其删除之外,还有其他方法可以解决这个问题吗?在当今的浏览器中,处理这个问题的正确方法是什么

我正在Windows上用谷歌Chrome进行测试

JSFiddle:

根据您的问题回答:有时(大约8个中的1个),在选择文件后,输入事件不会在选择文件后触发

我可以通过使用Opera(版本55.0.2994.61,目前最新版本)的
input
change
事件来确认此行为。每25次中就有1次

解决方案 这是因为有时您的输入元素对象在文件对话框关闭后被删除,因为它不再使用。当它发生时,您没有可以接收
输入
更改
事件的目标

要解决此问题,只需在创建为隐藏对象后将输入元素添加到DOM的某个位置,如下所示:

fileInputEl.style.display = 'none';
document.body.appendChild(fileInputEl);
document.body.removeChild(fileInputEl);
然后,当触发事件时,您可以按如下方式删除它:

fileInputEl.style.display = 'none';
document.body.appendChild(fileInputEl);
document.body.removeChild(fileInputEl);
完整示例

函数selectFile()
{
var fileInputEl=document.createElement('input');
fileInputEl.type='file';
fileInputEl.accept='image/*';
//通过这种方式,您可以看到选择了多少文件(仅用于测试):
fileInputEl.multiple='multiple';
fileInputEl.style.display='none';
document.body.appendChild(fileInputEl);
fileInputEl.addEventListener('input',函数(e)
{
//在这里处理文件。。。
log('您已选择'+fileInputEl.files.length+'个文件');
document.body.removeChild(fileInputEl);
});  
尝试
{
fileInputEl.dispatchEvent(新建MouseeEvent('click'));
}
捕获(e)
{
log('鼠标事件错误:\n'+e.message);
//待办事项:
//在IE/MS Edge中创建和触发合成事件:
//https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/dn905219(v=vs.85)
}
}

这是一个非常有趣的bug,我无法复制它

您这样处理文件输入有什么原因吗?是因为你想尝试和设计它吗

我阅读,然后应用它所做的。我发现这很有效。本文试图做的是在label标记上使用for属性将标签连接到输入。然后在CSS和JavaScript中,文件输入标记被隐藏,标签本质上充当“按钮”

例如

注意:我确实对代码做了一些修改,但所有这些都归功于Osvaldas Valutis,他是CoDrops上面提到的文章的作者

var inputs=document.querySelectorAll('.inputfile');
inputs.forEach(输入=>{
var label=input.nextElementSibling,
labelVal=label.innerHTML;
input.addEventListener('change',函数(e){
var fileName='';
如果(this.files&&this.files.length>1)
fileName=(this.getAttribute('data-multiple-caption')| |').replace('{count}',this.files.length);
其他的
fileName=e.target.value.split('\\').pop();
如果(文件名)
label.querySelector('span').innerHTML=文件名;
其他的
label.innerHTML=labelVal;
});
});
*{
字体系列:无衬线;
字体大小:300;
}
.inputfile{
显示:无;
}
.inputfile+标签{
字号:1.25em;
字号:700;
颜色:白色;
背景色:暗色;
显示:内联块;
填充:10px;
边界半径:10px;
边框:1px暗色实心;
光标:指针;
}
.inputfile+标签:悬停{
背景色:暗色;
}


选择一个文件
这似乎是一个浏览器错误/侥幸,可能与垃圾收集有关。我可以通过将文件输入添加到文档中来解决此问题:

fileInputEl.style.display = 'none';
document.querySelector('body').appendChild(fileInputEl);
完成后,可通过以下方式进行清理:

fileInputEl.remove();

为什么对文件输入使用
input
事件?
change
不是更合适吗?似乎在Firefox上运行良好Windows 10上的Google chrome 69.0.3497.92,每次我选择一个文件时都会触发事件。@munimuna。。。谢谢你的测试!想想看,我在Android上的Chrome也有这个问题。我想知道这是否是最近修复的错误。我已经有这个问题至少3或4年了,但在今天下午重新启动并获得Chrome更新后,我无法复制它。(无论哪个版本改变了标签的用户界面。我现在在v69.0.3497.100上。)如果有一天我给它添加了赏金,问题就解决了,这将是一个奇怪的巧合。也许多次访问该页面或使用JSFIDLE会产生副作用。有趣的是,在chrome for mac上似乎没有问题,只是连续18次选择了一个文件而没有发现错误。我很高兴听到你能够重现这个问题!然而,我怀疑setInterval解决方案不是最理想的。如果这是有效的,那么我们对这种行为有一些可能的解释。其中之一是未收集对输入元素的引用(因为它在正在进行的计时器中被引用),这允许稍后对其触发事件。(我的怀疑是,尽管附加了事件处理程序,输入元素还是很早就被收集了。)另一种可能的解释是,事件侦听器直到后来才绑定,这对我来说似乎是个bug。(续)我希望熟悉浏览器内部的人能够解释哪一个是正确的,或者如果有其他解释的话我没有。。。我刚刚颁发了赏金?@Br