在Chrome浏览器中,点击“取消”后清除文件的input type="file"。

17

<input type="file"/> 在 Chrome 中,单击“选择文件”模态窗口中的“取消”后,文件及其路径被清除;而在火狐和IE中,单击“取消”后,文件仍保持不变。是否有办法在 Chrome 中改变这种行为?


1
你能否创建一个fiddle并向我们展示你的意思?谢谢 :) - GFP
@Powerslave请考虑从下面的答案中标记一个首选解决方案。 - Youp Bernoulli
这被标记为“不予修复” https://bugs.chromium.org/p/chromium/issues/detail?id=2508 - Minh Nghĩa
4个回答

2

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>

https://jsfiddle.net/dqL97q0b/1/


1

本文不包括的内容

此解决方案未涵盖 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"/>


0

是的,如果你想使用基于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();
       }
    }
}

-1
简单而有效的解决方案:将文件的引用保存在变量中。每次输入的更改事件被触发时,您都会进行检查:
if(input.files[0]) // truthy, falsey
{
  var file = input.files[0];
}

所以file将包含最新选择的文件,当用户打开对话框但取消文件引用时,文件引用不会更改,仍然包含先前选择的文件。


不,我觉得虽然它提供了一个解决手动实现 OP 所寻找的行为的方法,但它并没有真正回答他们的问题:“我能否默认更改 Chrome 的工作方式?”;@Medhi 的答案最直接地回答了这个问题,但缺乏对问题的建议解决方案。我认为值得点赞的答案应该具备这两个组成部分。 - Daniel Brady

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接