2016-08-09 107 views
3

我有一个基本的input[file]元素,我隐藏。当你点击#holder时,会弹出一个文件浏览器。但选择一个文件会触发console.log()行被执行两次(在我的电脑上)。文件输入触发器改变事件两次(或更多)

请注意:以下代码会使我的Chrome选项卡崩溃。

您应该将其作为单独的文件运行。无法提供“正常”演示,但这是最接近MCVE

var element = document.getElementById('holder'); 
 

 
element.onclick = function(e) { 
 
    var input = document.getElementById('file-input'); 
 
    input.click(); 
 
    input.addEventListener("change", function(evt) { 
 
    console.log(evt); 
 
    Phimij.addFiles(input.files); 
 
    }, false); 
 
};
#holder { 
 
    border: 10px dashed #ccc; 
 
    width: 300px; 
 
    height: 300px; 
 
    margin: 20px auto; 
 
} 
 
#holder.hover { 
 
    border: 10px dashed #333; 
 
} 
 
#file-input { 
 
    display: none; 
 
}
<div id="holder"> 
 
    <input type="file" multiple id="file-input" /> 
 
</div>

+3

你在父每次点击事件添加事件侦听器。另外,如果你点击输入,它也会触发输入的点击 – Kaiido

回答

2

click事件泡沫了祖先树。这意味着点击你的input会触发你的#holder元素,并触发你的click处理器。在#holderclick处理程序中,您将触发input上的click事件。这就是为什么你的浏览器崩溃:你触发了一个无限循环。

解决方法是在input上挂钩click,并告诉它不要冒泡(传播);看到标记线(但请继续阅读,下面将进一步说明):

var element = document.getElementById('holder'); 
 
// **** Added vvvv 
 
document.getElementById('file-input').addEventListener("click", function(evt) { 
 
    evt.stopPropagation(); 
 
}, false); 
 
// *** Added ^^^^ 
 
element.onclick = function(e) { 
 
    var input = document.getElementById('file-input'); 
 
    input.click(); 
 
    input.addEventListener("change", function(evt) { 
 
    console.log(evt); 
 
    // Phimij.addFiles(input.files); 
 
    }, false); 
 
};
#holder { 
 
    border: 10px dashed #ccc; 
 
    width: 300px; 
 
    height: 300px; 
 
    margin: 20px auto; 
 
} 
 
#holder.hover { 
 
    border: 10px dashed #333; 
 
} 
 
#file-input { 
 
    display: none; 
 
}
<div id="holder"> 
 
    <input type="file" multiple id="file-input" /> 
 
</div>


还有一些其他的东西我会改变。你 a change处理程序的输入每次click#holder;你真的只想做那一次。我还会在触发点击之前添加该处理程序。

因此,对于它的价值,一些变化我会做:

var element = document.getElementById('holder'); 
 
var input = document.getElementById('file-input'); 
 

 
element.addEventListener("click", function() { 
 
    input.click(); 
 
}, false); 
 

 
input.addEventListener("click", function(evt) { 
 
    evt.stopPropagation(); 
 
}, false); 
 
input.addEventListener("change", function(evt) { 
 
    console.log(evt); 
 
    // Phimij.addFiles(input.files); 
 
}, false);
#holder { 
 
    border: 10px dashed #ccc; 
 
    width: 300px; 
 
    height: 300px; 
 
    margin: 20px auto; 
 
} 
 
#holder.hover { 
 
    border: 10px dashed #333; 
 
} 
 
#file-input { 
 
    display: none; 
 
}
<div id="holder"> 
 
    <input type="file" multiple id="file-input" /> 
 
</div>

+0

@Kaiido:LOL,我也是这么做的。我真的应该预先。 –

+0

对不起,我的英文不太好。你的前两句意味着每个子元素都会触发所有父母的点击事件?另外,感谢您的详细回答和示例! –

+1

@IvankaTodorova:是的,确切的。点击一个元素会在该元素上运行任何点击处理程序,然后将气泡(“传播”)传递给它的父级,并在该元素上运行任何点击处理程序,然后冒泡到其*父级并在其上运行任何点击处理程序,等等。 ,直到它到达文档的根部。请参阅DOM UI Events规范中的[此图](https://www.w3.org/TR/uievents/#event-flow)。 (您可以忽略“捕获”部分,它基本上不用于Web开发,因为IE9直到IE9才支持它。)大多数(但不是全部)DOM事件冒泡。 –