设置文本或数字输入字段的值非常简单,只需执行以下操作:
代码语言:javascript复制const input = document.querySelector('input');
input.value = '新值';
但是,对于文件输入字段,情况略有不同。与文本或数字字段不同,简单地设置文件输入字段的值是无效的。
当用户手动选择文件时,文件输入字段的值如下所示:
代码语言:javascript复制input.addEventListener('change', (event) => {
console.log(event.target.value);
// => C:\fakepath\file.txt
});
常见的误解和尝试
用户系统中文件路径 C:fakepathfile.txt 在浏览器中是被隐藏的,设置值属性为其他值不会有任何区别,因为浏览器不依赖输入的值来获取文件的引用。在幕后,浏览器在用户磁盘上保留了文件的内部引用,但这并不对 DOM 可见,也不应更改。但你可以通过在输入元素上编程设置文件属性来修改文件。
不,这并不像以下这么简单:
代码语言:javascript复制const file = '路径/到/我的文件.ext';
input.files = file;
// 或者
input.files[0] = file;
或者创建一个文件对象并将其分配给 files0。
代码语言:javascript复制const myFile = new File(['我的文件内容'], 'my_file.txt');
input.files[0] = myFile; // 不起作用
input.files = [myFile]; // 不起作用
以上尝试也不会生效,因为 files 对象是 FileList 接口的一种类型,它不是内部数组,而是类似数组的对象。可以在 w3c 规范中查看。
我的方法
在寻找答案时,我在 Stackoverflow 上得到了一堆不赞同的回答和否定。有一个答案告诉 PHP 用户,如果有解决方法,它最终会被 Chrome 构建者禁用。然而,这与此处的解决方案不同,因为要禁用此功能将意味着禁用拖放功能模拟(在大多数测试库中使用),自定义拖放交互或自定义剪贴板操作。这个解决方案是基于拖放功能的。
以下是解决方案:
代码语言:javascript复制const fileInput = document.querySelector('input[type="file"]');
// 准备好你的文件
const myFileContent = ['我的文件内容'];
const myFileName = 'my_file.txt';
const myFile = new File(myFileContent, myFileName);
// 创建数据传输对象。类似于 `drop` 事件中的 `event.dataTransfer`
const dataTransfer = new DataTransfer();
// 将文件添加到对象的文件列表中
dataTransfer.items.add(file);
// 将文件列表保存到一个新变量中
const fileList = dataTransfer.files;
// 将输入的 `files` 设置为文件列表
fileInput.files = fileList;
根据你的使用情况,你可以触发一个 change 和/或 input 事件以模拟实际用户交互:
代码语言:javascript复制fileInput.dispatchEvent(new Event('change', { bubbles: true }));
// 和/或
fileInput.dispatchEvent(new Event('input', { bubbles: true }));
在我的情况下,我遇到了一个问题,我需要更改表单中文件输入字段的文件内容,但我无法访问代码。表单的底层代码会监视文件输入更改或 dragover/drop JavaScript 事件。这个解决方案帮助我完美地模拟了用户交互,希望它对你的用例也有帮助。
我正在参与2023腾讯技术创作特训营第四期有奖征文,快来和我瓜分大奖!