从代码生成的INPUT元素中选择文件后,不会触发事件onChange [英] Event onChange won't trigger after files are selected from code-generated INPUT element

查看:328
本文介绍了从代码生成的INPUT元素中选择文件后,不会触发事件onChange的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在玩JavaScript并编写了一个简单的函数来创建 INPUT 元素( type =file)并模拟点击。

I'm playing with JavaScript and wrote simple function that creates INPUT element (type="file") and simulates click.

var createAndCallFileSelect = function () {
    var input = document.createElement ("input");
    input.setAttribute ("type", "file");
    input.addEventListener ("change", function () {
        console.log (this.files);
    }, false);
    input.click();
}

它大部分时间效果很好但有时它不会触发 onChange 选择文件时的事件(或与 INPUT上的多个属性一起使用的更多文件)。

It works great most of time but sometimes it doesn't fire onChange event when file is selected (or more files when used with multiple attribute on INPUT).

我知道当你重新选择同一个文件时, onChange 不会触发这不是这里的情况。它仅在我第一次使用此功能时才触发事件,有时仅触发。如果从对话框中选择了某些内容,则每次下一次点击通常会触发 onChange

I know that onChange won't fire when you re-select same file but clearly this is not the case here. It doesn't fire an event only first time I use this function, and sometimes only. Every next click normally fires onChange if something is selected from dialog.

已经尝试在此处及周围搜索此问题但似乎所有 onChange问​​题和解决方案都与重新选择同一文件的着名问题有关。

Already tried searching for this problem here and around but seems that all onChange problems and solutions are related to famous problem with re-selecting same file again.

我发现这种情况发生在最新的Opera上和Firefox,从未测试过其他浏览器。也。我试图等待整个页面加载但结果仍然相同 - 有时它在第一次调用时不会触发 onChange

I found this happens on latest Opera and Firefox, never tested with other browsers. Also. I tried to wait entire page to be loaded but result is still the same - sometimes it doesn't trigger onChange on first call.

任何人都可以向我解释为什么会这样吗? 我已经有解决方法代码,这不是问题,只需要解释为什么在创建INPUT并以这种方式调用时会发生这种情况。

Can anyone explain to me why this happens? I already have workaround code, that's not the question, just need explanation of why this happens when INPUT is created and called this way.

级联延迟

var function createAndCallFileSelect = function () {
    var input = document.createElement ("input");
    setTimeout (function () { // set type with 1s delay
        input.setAttribute ("type", "file");
        setTimeout (function () {  // attach event with 1s delay
            input.addEventListener ("change", function () {
                console.log (this.files);
            }, false);
            setTimeout (function () { // simulate click with 1s delay
                input.click();
            }, 1000);
        }, 1000);
    }, 1000);
}

这也不起作用。我试图延迟每一行的执行,以确保一切都以正确的顺序执行。调用后3秒打开文件选择对话框,但有时它会在选择文件后触发 onChange 事件。

This also doesn't work. I tried to delay execution of each line to be sure that everything is executed in right order. 3 seconds after call it opens file-select dialog but again, sometimes it doesn't fire onChange event after file is selected.

推荐答案

这是竞争条件。它取决于堆栈中的内容以及在调用同步文件浏览器阻止堆栈的其余部分完成之前某些事情可能需要多长时间。使用addeventlistener,它会将一个回调排队等待以后使用,当堆栈清除时,它将被事件循环拾取。如果堆栈未及时清除,则不会及时调用。我不能保证什么时候会运行。如果你像Pawel建议的那样使用setTimeout(fn,0),你将在放置事件监听器之后对click()函数进行排队。

It's a race condition. It's dependant on what is in the stack and how long certain things might take before the synchronous file browser is called to block the rest of the stack from finishing. With addeventlistener, it's queuing a callback for later use which will be picked up by the event loop when the stack clears. If the stack isn't cleared in time, it won't be called in time. There's no guarantee what will be run when. If you use setTimeout(fn, 0) as Pawel suggested, you'll queue the click() function to be called after the event listener has been placed.

这是一个伟大的视频,可视化我正在谈论的一切: https://www.youtube.com/watch? v = 8aGhZQkoFbQ

Here's a great video that visualizes everything I'm talking about: https://www.youtube.com/watch?v=8aGhZQkoFbQ

更新:
我在看了一下后发现了一些非常有趣的东西进一步......它只允许一次创建最多5个元素。我这样做了:

Update: I've noticed something very interesting with chrome after looking into this a bit further...it only allows up to 5 of those elements to be created at once. I did this:

for(var i = 0; i < 20; i += 1) {
    createAndCallFileSelect()
}

在那里有几个不同的数字...每次,任何大于5的数字只产生5个带5个回调的输入元素,而5和under产生正确的数量。

with several different numbers in there...and each time, any number greater than 5 only produced 5 input elements with 5 callbacks, while 5 and under produced the correct amount.

我也尝试了这个递归而不是使用for循环。 ..同样的结果。

I also tried this recursively instead of using the for loop...same results.

此外,我选择的文件越大,所需的时间越长,但最终它会在处理文件后调用回调。到目前为止,这项测试都是以铬为主。

Also, the larger the file I select, the longer it takes, but eventually it'll call the callback after it processes the file. This testing so far has all been in chrome.

这篇关于从代码生成的INPUT元素中选择文件后,不会触发事件onChange的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆