Javascript <input type="file"> 即使选择了文件,文件列表也是空的
Javascript <input type="file"> has empty file list even when file is selected
我正在尝试在 HTML 和 Javascript 中进行简单的文件上传。
我设置它的方式是让一个 <input type="file" id="file-upload-input"/>
和一个 loadFile
函数订阅它的 onChange
事件。 (我把这个 input
隐藏起来只是因为它看起来很糟糕。)
然后我有一个 <button/>
函数 handleBrowseClick
订阅了它的 onclick
事件。
以上两个控件似乎工作正常:当我单击我的 <button/>
时,调用 handleBrowseClick
,它单击我的 <input type="file">
,导致文件对话框打开。但是,一旦我 select 一个文件并在对话框中按 "open" 就会出现问题(这会触发 <input type="file">
的 onChange
事件,从而调用我的 loadFile
功能)。
如您在 Javascript 中所见,此时尝试通过获取我的 <input type="file">
、访问其 files
属性 并尝试读取文件获取该数组的第一个元素,以便我可以使用 FileReader
从中读取(效果很好)。
然而,无论我 select 是什么文件,files
数组总是空的(因此我的 alert
打印出 "# Files Selected: 0"
)!经过广泛调试和缩小问题范围后,我发现在 handleBrowseClick()
中,如果我删除稍微修改 HTML 正文的调试代码,那么文件上传突然就完美了! (alert
打印出 "# Files Selected: 1"
。)
所以这是我的问题:为什么
- 仅修改 HTML 的正文(但不影响任何控件)
- 与文件上传功能无关
阻止我的文件上传工作?
function handleBrowseClick()
{
document.getElementById("upload-file-input").click();
// if I comment out this line, then the file upload works
document.body.innerHTML += "<br/>Browsing...";
}
function loadFile()
{
var elem = document.getElementById("upload-file-input");
var files = elem.files;
alert("# Files Selected: " + files.length);
var file = files[0];
if (!file) return;
var reader = new FileReader();
reader.onload = function()
{
// do stuff with reader.result
// example:
document.getElementById("file-content").innerHTML = reader.result;
};
reader.readAsText(file);
}
<!DOCTYPE html>
<html>
<head>
<script src="course_chart.js"></script>
</head>
<body>
<input type="file" accept=".txt" id="upload-file-input" style="display: none" onChange="javascript:loadFile()"/>
<button onclick="javascript:handleBrowseClick()" id="choose-file-button">Load File</button>
<div id="file-content"></div>
</body>
</html>
使用 innerHTML +=
解释 HTML,它不仅添加了一些文本,还删除了所有内容并重新创建了整个 HTML。见 https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML:
For that reason, it is recommended you not use innerHTML when
inserting plain text; instead, use node.textContent. This doesn't
interpret the passed content as HTML, but instead inserts it as raw
text.
因此在您的情况下,调用之前的 input
元素与调用之后的元素不同。您可以在下面的 jsfiddle 中看到,比较调用之前和之后的节点,当您使用 innerHTML +=
时,您会发现它不是同一个元素,即使 HTML 是相同的。
http://jsfiddle.net/6nja0v6b/1/
编辑
原始答案中的引用可能会导致混淆,虽然它描述了 innerHTML 的作用,但上下文不是问题之一。可以在此处找到更准确的描述:https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#widl-Element-innerHTML。特别是:
element . innerHTML [ = value ]
Returns a fragment of HTML or XML that represents the element's
contents.
Can be set, to replace the contents of the element with nodes parsed
from the given string.
和
On setting, these steps must be run:
Let fragment be the result of invoking the fragment parsing algorithm
with the new value as markup, and the context object as the context
element. Replace all with fragment within the context object.
这可以通过在 node
上添加一个 eventListener
,然后调用 innerHTML
在该节点上插入完全相同的 HTML 来非常简单地说明。虽然文档看起来相同,但行为不一致,因为 innerHTML
重新创建节点结构,innerHTML
调用之前的节点与调用之后的节点不同。见片段:
var container = document.querySelector("#container");
var testElem = document.querySelector("#testElement");
var replaceBtn = document.querySelector("#replaceHtml");
var compareBtn = document.querySelector("#compare");
//We add the listener on original testElem
testElement.addEventListener('click', function(e) {
alert("eventListener is working");
})
//After using innerHTML, event listener won't work and compare will be false
replaceBtn.onclick = function() {
//This doesn't change the HTML, but replaces the node
container.innerHTML = container.innerHTML;
}
//Use this to compare original testElement to new one. After innerHTML is used, it's not the same node.
compare.onclick = function() {
alert("Is testElem \=\=\= document.querySelector(\"testElement\"): " + (testElem === document.querySelector("#testElement")));
}
#testElement {
width: 100px;
height: 100px;
background-color: blue;
}
<div id="container">
<div id="testElement"></div>
</div>
<button id="replaceHtml">Replace HTML</button>
<button id="compare">Compare nodes</button>
我正在尝试在 HTML 和 Javascript 中进行简单的文件上传。
我设置它的方式是让一个 <input type="file" id="file-upload-input"/>
和一个 loadFile
函数订阅它的 onChange
事件。 (我把这个 input
隐藏起来只是因为它看起来很糟糕。)
然后我有一个 <button/>
函数 handleBrowseClick
订阅了它的 onclick
事件。
以上两个控件似乎工作正常:当我单击我的 <button/>
时,调用 handleBrowseClick
,它单击我的 <input type="file">
,导致文件对话框打开。但是,一旦我 select 一个文件并在对话框中按 "open" 就会出现问题(这会触发 <input type="file">
的 onChange
事件,从而调用我的 loadFile
功能)。
如您在 Javascript 中所见,此时尝试通过获取我的 <input type="file">
、访问其 files
属性 并尝试读取文件获取该数组的第一个元素,以便我可以使用 FileReader
从中读取(效果很好)。
然而,无论我 select 是什么文件,files
数组总是空的(因此我的 alert
打印出 "# Files Selected: 0"
)!经过广泛调试和缩小问题范围后,我发现在 handleBrowseClick()
中,如果我删除稍微修改 HTML 正文的调试代码,那么文件上传突然就完美了! (alert
打印出 "# Files Selected: 1"
。)
所以这是我的问题:为什么
- 仅修改 HTML 的正文(但不影响任何控件)
- 与文件上传功能无关
阻止我的文件上传工作?
function handleBrowseClick()
{
document.getElementById("upload-file-input").click();
// if I comment out this line, then the file upload works
document.body.innerHTML += "<br/>Browsing...";
}
function loadFile()
{
var elem = document.getElementById("upload-file-input");
var files = elem.files;
alert("# Files Selected: " + files.length);
var file = files[0];
if (!file) return;
var reader = new FileReader();
reader.onload = function()
{
// do stuff with reader.result
// example:
document.getElementById("file-content").innerHTML = reader.result;
};
reader.readAsText(file);
}
<!DOCTYPE html>
<html>
<head>
<script src="course_chart.js"></script>
</head>
<body>
<input type="file" accept=".txt" id="upload-file-input" style="display: none" onChange="javascript:loadFile()"/>
<button onclick="javascript:handleBrowseClick()" id="choose-file-button">Load File</button>
<div id="file-content"></div>
</body>
</html>
使用 innerHTML +=
解释 HTML,它不仅添加了一些文本,还删除了所有内容并重新创建了整个 HTML。见 https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML:
For that reason, it is recommended you not use innerHTML when inserting plain text; instead, use node.textContent. This doesn't interpret the passed content as HTML, but instead inserts it as raw text.
因此在您的情况下,调用之前的 input
元素与调用之后的元素不同。您可以在下面的 jsfiddle 中看到,比较调用之前和之后的节点,当您使用 innerHTML +=
时,您会发现它不是同一个元素,即使 HTML 是相同的。
http://jsfiddle.net/6nja0v6b/1/
编辑
原始答案中的引用可能会导致混淆,虽然它描述了 innerHTML 的作用,但上下文不是问题之一。可以在此处找到更准确的描述:https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#widl-Element-innerHTML。特别是:
element . innerHTML [ = value ]
Returns a fragment of HTML or XML that represents the element's contents.
Can be set, to replace the contents of the element with nodes parsed from the given string.
和
On setting, these steps must be run:
Let fragment be the result of invoking the fragment parsing algorithm with the new value as markup, and the context object as the context element. Replace all with fragment within the context object.
这可以通过在 node
上添加一个 eventListener
,然后调用 innerHTML
在该节点上插入完全相同的 HTML 来非常简单地说明。虽然文档看起来相同,但行为不一致,因为 innerHTML
重新创建节点结构,innerHTML
调用之前的节点与调用之后的节点不同。见片段:
var container = document.querySelector("#container");
var testElem = document.querySelector("#testElement");
var replaceBtn = document.querySelector("#replaceHtml");
var compareBtn = document.querySelector("#compare");
//We add the listener on original testElem
testElement.addEventListener('click', function(e) {
alert("eventListener is working");
})
//After using innerHTML, event listener won't work and compare will be false
replaceBtn.onclick = function() {
//This doesn't change the HTML, but replaces the node
container.innerHTML = container.innerHTML;
}
//Use this to compare original testElement to new one. After innerHTML is used, it's not the same node.
compare.onclick = function() {
alert("Is testElem \=\=\= document.querySelector(\"testElement\"): " + (testElem === document.querySelector("#testElement")));
}
#testElement {
width: 100px;
height: 100px;
background-color: blue;
}
<div id="container">
<div id="testElement"></div>
</div>
<button id="replaceHtml">Replace HTML</button>
<button id="compare">Compare nodes</button>