2016-08-09 151 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事件冒泡。 –