我的Web应用程序上有一个按钮,该按钮在click事件处理程序中具有以下代码:
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上的Google Chrome浏览器进行测试。
JSFiddle:http://jsfiddle.net/pja1d5om/2/
答案 0 :(得分:2)
回答您的问题: 有时(大约8个中的1个),选择文件后,选择文件后不会触发输入事件。>
我可以通过使用Google Chrome browser engine "Blink"的Opera(版本55.0.2994.61,当前最新版本)通过input
和change
事件来确认这种行为。它发生在25分之一左右。
之所以发生这种情况,是因为有时您的输入元素对象在文件对话框关闭后被删除了,因为它不再使用了。而且当发生这种情况时,您还没有可以接收input
或change
事件的目标。
要解决此问题,只需在创建隐藏对象后将输入元素添加到DOM的某处,如下所示:
fileInputEl.style.display = 'none';
document.body.appendChild(fileInputEl);
然后,当事件触发时,您可以将其删除,如下所示:
document.body.removeChild(fileInputEl);
完整示例
function selectFile()
{
var fileInputEl = document.createElement('input');
fileInputEl.type = 'file';
fileInputEl.accept = 'image/*';
//on this way you can see how many files you select (is for test only):
fileInputEl.multiple = 'multiple';
fileInputEl.style.display = 'none';
document.body.appendChild(fileInputEl);
fileInputEl.addEventListener('input', function(e)
{
// Handle files here...
console.log('You have selected ' + fileInputEl.files.length + ' file(s).');
document.body.removeChild(fileInputEl);
});
try
{
fileInputEl.dispatchEvent(new MouseEvent('click'));
}
catch(e)
{
console.log('Mouse Event error:\n' + e.message);
// TODO:
//Creating and firing synthetic events in IE/MS Edge:
//https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/dn905219(v=vs.85)
}
}
<input type="button" onclick="selectFile()" value="Select file">
从您的赏金描述中引用: 赏金将奖励给……展示出适当解决方法的人。
我建议的旧解决方法(现已不相关)
我们可以使用setInterval
函数来检查输入值是否已更改。我们将intervalID
保存为新的fileInputEl
作为属性。因为我们总是创建一个新的文件输入元素,所以它的值在启动时(每次单击按钮时)总是空的。如果更改了该值,则可以在将其与空字符串进行比较时检测到它。然后,当发生这种情况时,我们将fileInputEl
传递给fileInputChanged()
函数,并清除/停止间隔函数。
function selectFile()
{
var fileInputEl = document.createElement('input');
fileInputEl.type = 'file';
fileInputEl.accept = 'image/*';
//on this way you can see how many files you select (is for test only):
fileInputEl.multiple = 'multiple';
fileInputEl.intervalID = setInterval(function()
{
// because we always create a new file input element then
// its value is always empty, but if not then it was changed:
if(fileInputEl.value != '')
fileInputChanged(fileInputEl);
}, 100);
try
{
fileInputEl.dispatchEvent(new MouseEvent('click'));
}
catch(e)
{
console.log('Mouse Event error:\n' + e.message);
// TODO:
//Creating and firing synthetic events in IE/MS Edge:
//https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/dn905219(v=vs.85)
}
}
function fileInputChanged(obj)
{
// Handle files here...
console.log('You have selected ' + obj.files.length + ' file(s).');
clearInterval(obj.intervalID);
}
<input type="button" onclick="selectFile()" value="Select file">
答案 1 :(得分:0)
那是您遇到的一个非常有趣的错误,我无法复制它。
您是否有理由按自己的方式处理文件输入?是因为您想尝试设计样式吗?
我读了this article,然后应用了它所做的事情。我发现这很好。本文试图做的是将一个标签连接到输入,标签标签上带有for属性。然后,在CSS和JavaScript中,文件输入标签被隐藏,标签实际上是“按钮”。
例如...
注意我确实对代码进行了一些更改,但全部归功于Codrops以上文章的作者Osvaldas Valutis。
var inputs = document.querySelectorAll('.inputfile');
inputs.forEach(input => {
var label = input.nextElementSibling,
labelVal = label.innerHTML;
input.addEventListener('change', function(e) {
var fileName = '';
if (this.files && this.files.length > 1)
fileName = (this.getAttribute('data-multiple-caption') || '').replace('{count}', this.files.length);
else
fileName = e.target.value.split('\\').pop();
if (fileName)
label.querySelector('span').innerHTML = fileName;
else
label.innerHTML = labelVal;
});
});
* {
font-family: sans-serif;
font-weight: 300;
}
.inputfile {
display: none;
}
.inputfile+label {
font-size: 1.25em;
font-weight: 700;
color: white;
background-color: darkred;
display: inline-block;
padding: 10px;
border-radius: 10px;
border: 1px darkred solid;
cursor: pointer;
}
.inputfile+label:hover {
background-color: darkred;
}
<input type="file" name="file" id="file" class="inputfile" data-multiple-caption="{count} files selected" multiple />
<label for="file">Choose a file <span></span></label>
现在,我知道这可能并不是您要找的东西,但这可能是您可以尝试的替代解决方案。
答案 2 :(得分:0)
这似乎是浏览器的错误/漏洞,可能与垃圾回收有关。我可以通过将输入的文件添加到文档中来解决此问题:
fileInputEl.style.display = 'none';
document.querySelector('body').appendChild(fileInputEl);
完成后,可以使用以下方法清除它:
fileInputEl.remove();