<input type="file"/>
在 Chrome 中,单击“选择文件”模态窗口中的“取消”后,文件及其路径被清除;而在火狐和IE中,单击“取消”后,文件仍保持不变。是否有办法在 Chrome 中改变这种行为?
<input type="file"/>
在 Chrome 中,单击“选择文件”模态窗口中的“取消”后,文件及其路径被清除;而在火狐和IE中,单击“取消”后,文件仍保持不变。是否有办法在 Chrome 中改变这种行为?
https://jsfiddle.net/dqL97q0b/1/
这里有一个解决方法,使得Chrome在按下取消时无法删除用户现有的文件。
代码注释: 当用户打开文件选择器并且已经选择了文件时,这会克隆Dom元素。 然后,如果用户在Chrome中点击取消,它会触发change事件监听器,并且值将为“”,因此在这种特定情况下,我会删除现在为空的文件选择器,并恢复克隆。
注意:每个文件选择器Dom元素都需要一个唯一的ID,以便可以正确存储和检索克隆。
注意:大部分代码只是用于记录日志,以展示如何工作,特别是我想强调的是,如果您在Dom元素中使用内联事件监听器,例如onclick="fileClicked(event)",则不需要重新附加事件监听器到克隆上。
<!doctype html><html><head></head><body>
<h2>Fix for Chrome Removing File when 'cancel' clicked</h2>
Upload Image: <input id="imageUpload" type="file" onclick="fileClicked(event)" onchange="fileChanged(event)">
<br/><br/>
<label for="videoUpload">Upload Video:</label> <input id="videoUpload" type="file" onclick="fileClicked(event)" onchange="fileChanged(event)">
<br/><br/>
<div id="log"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
//This is All Just For Logging:
var debug = true;//true: add debug logs when cloning
var evenMoreListeners = true;//demonstrat re-attaching javascript Event Listeners (Inline Event Listeners don't need to be re-attached)
if (evenMoreListeners) {
var allFleChoosers = $("input[type='file']");
addEventListenersTo(allFleChoosers);
function addEventListenersTo(fileChooser) {
fileChooser.change(function (event) { console.log("file( #" + event.target.id + " ) : " + event.target.value.split("\\").pop()) });
fileChooser.click(function (event) { console.log("open( #" + event.target.id + " )") });
}
}
var clone = {};
// FileClicked()
function fileClicked(event) {
var fileElement = event.target;
if (fileElement.value != "") {
if (debug) { console.log("Clone( #" + fileElement.id + " ) : " + fileElement.value.split("\\").pop()) }
clone[fileElement.id] = $(fileElement).clone(); //'Saving Clone'
}
//What ever else you want to do when File Chooser Clicked
}
// FileChanged()
function fileChanged(event) {
var fileElement = event.target;
if (fileElement.value == "") {
if (debug) { console.log("Restore( #" + fileElement.id + " ) : " + clone[fileElement.id].val().split("\\").pop()) }
clone[fileElement.id].insertBefore(fileElement); //'Restoring Clone'
$(fileElement).remove(); //'Removing Original'
if (evenMoreListeners) { addEventListenersTo(clone[fileElement.id]) }//If Needed Re-attach additional Event Listeners
}
//What ever else you want to do when File Chooser Changed
}
</script>
</body></html>
此解决方案未涵盖 Chrome 最初不引入此功能的原因,即删除按钮。虽然考虑到这一点,删除按钮将是一个非常简单的实现。
每当输入选择文件时,此代码将所选文件保存为对象数组,并在文件输入未指定文件选择时(已取消),检索该文件。
// Globally declare the array
// If your javascript isn't refreshed each time you visit the inputs, you'll want to clear this on form submit
array = []
// Add New file
// Replace current file
$("input").change(function(event) {
let file_list = event.target.files
let key = event.target.id
// When we change the files in our input, we persist the file by input
// Persistence before assignment will always result in the most recent file choice
persist_file(array, file_list, key)
// Assign the targets files to whatever is persisted for it
event.target.files = element_for(array, key).file_list
});
// @doc Pushes or Replaces {key: <key>, file_list: <FileList>} objects into an array
function persist_file(array, file_list, key) {
if(file_list.length > 0) {
if(member(array, key)) {
element_for(array, key).file_list = file_list;
}else {
array.push({key: key, file_list: file_list})
}
}
}
// @doc Determines if the <key> exists in an object element of the <array>
function member(array, key) {
return array.some((element, index) => {
return element.key == key
})
}
// @doc Get element in array by key
function element_for(array, key) {
return array.find((function(obj, index) {return obj.key === key}))
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type='file' id="input_0"/><br>
<input type='file' id="input_1"/><br>
<input type='file' id="input_2"/>
是的,如果你想使用基于jQuery的解决方案,那么这是Chrome的一个问题,你可以使用以下方法。
// Defining a global variable to persist data
let $old_value;
// if input field id is file and its inside a div which has id file-wrapper
$('#file_wrapper').on('change', '#file', function() {
const img = this.files[0];
// If image selected
if (img) {
// Change thumbnail or what your want
// Cloning the input filed value for future
old_value = $(this).clone();
} else {
// If no file selected or canceled and previously selected an image
if (old_value) {
$(this).remove();
let new_img = $('#file_wrapper').append(old_img);
old_img = new_img.clone();
}
}
}
if(input.files[0]) // truthy, falsey
{
var file = input.files[0];
}
所以file
将包含最新选择的文件,当用户打开对话框但取消文件引用时,文件引用不会更改,仍然包含先前选择的文件。