use*_*241 40 html javascript filereader dom-events
我正在使用FileReader API来读取本地文件.
<input type="file" id="filesx" name="filesx[]" onchange="readmultifiles(this.files)" multiple="" />
<script>
function readmultifiles(files) {
var ret = "";
var ul = document.querySelector("#bag>ul");
while (ul.hasChildNodes()) {
ul.removeChild(ul.firstChild);
}
for (var i = 0; i < files.length; i++) //for multiple files
{
var f = files[i];
var name = files[i].name;
alert(name);
var reader = new FileReader();
reader.onload = function(e) {
// get file content
var text = e.target.result;
var li = document.createElement("li");
li.innerHTML = name + "____" + text;
ul.appendChild(li);
}
reader.readAsText(f,"UTF-8");
}
}
</script>
Run Code Online (Sandbox Code Playgroud)
如果输入包含2个文件:
file1 ---- "content1"
file2 ---- "content2"
Run Code Online (Sandbox Code Playgroud)
我得到这个输出:
file2__content1
file2__content2
Run Code Online (Sandbox Code Playgroud)
如何修复要显示的代码:
file1__content1
file2__content2
Run Code Online (Sandbox Code Playgroud)
Ben*_*Lee 91
问题是你正在运行的循环,现在,但你设置回调越来越运行后(事件触发时).当它们运行时,循环结束并保持在最后一个值.因此,在您的情况下,它将始终显示"file2"作为名称.
解决方案是将文件名放在一个闭包中.一种方法是创建一个立即调用的函数表达式(IIFE)并将该文件作为参数传递给该函数:
for (var i = 0; i < files.length; i++) { //for multiple files
(function(file) {
var name = file.name;
var reader = new FileReader();
reader.onload = function(e) {
// get file content
var text = e.target.result;
var li = document.createElement("li");
li.innerHTML = name + "____" + text;
ul.appendChild(li);
}
reader.readAsText(file, "UTF-8");
})(files[i]);
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以定义命名函数并将其称为正常:
function setupReader(file) {
var name = file.name;
var reader = new FileReader();
reader.onload = function(e) {
// get file content
var text = e.target.result;
var li = document.createElement("li");
li.innerHTML = name + "____" + text;
ul.appendChild(li);
}
reader.readAsText(file, "UTF-8");
}
for (var i = 0; i < files.length; i++) {
setupReader(files[i]);
}
Run Code Online (Sandbox Code Playgroud)
编辑:只使用let而不是var在循环中。这解决了OP的问题(但仅在2015年才引入)。
旧答案(一个有趣的解决方法):
虽然它不完全可靠或不适合未来,但值得一提的是,也可以通过向FileReader对象添加属性来实现:
var reader = new FileReader();
reader._NAME = files[i].name; // create _NAME property that contains filename.
Run Code Online (Sandbox Code Playgroud)
然后通过访问它e的内onload回调函数:
li.innerHTML = e.target._NAME + "____" + text;
Run Code Online (Sandbox Code Playgroud)
即使reader在像这样的循环中多次替换了变量i,new FileReader对象也是唯一的,并保留在内存中。reader.onload通过e参数可以在函数中访问它。通过在存储附加数据reader对象时,它被保持在存储器中且可通过reader.onload经由e.target事件参数。
这解释了为什么您的输出是:
file2 __content1
file2__content2
并不是:
file1__content1
file2__content2
内容正确显示,因为它e.target.result是FileReader对象本身的属性。已经FileReader包含默认的文件名属性,它可能已被使用,这整个烂摊子完全避免。
这称为扩展宿主对象(如果我了解本机对象之间的区别...)。FileReader是在这种情况下扩展的宿主对象。许多专业开发人员认为这样做是不好的做法和/或邪恶的。如果_NAME将来使用冲突,可能会发生冲突。此功能未在任何规范中进行记录,因此将来可能会中断,并且可能无法在较旧的浏览器中使用。
就个人而言,我没有通过向宿主对象添加其他属性来遇到任何问题。假定属性名称具有足够的唯一性,浏览器不会禁用它,并且以后的浏览器也不会对这些对象进行太多更改,那么它应该可以正常工作。
以下是一些可以很好地解释这一点的文章:
http://kendsnyder.com/extending-host-objects-evil-extending-native-objects-not-evil-but-risky/
http://perfectionkills.com/whats-wrong-with-extending-the-dom/
还有一些有关问题本身的文章:
http://tobyho.com/2011/11/02/callbacks-in-loops/
使用let代替var,因为声明的变量只能在一个循环中使用。
for (let i = 0; i < files.length; i++) //for multiple files
{
let f = files[i];
let name = files[i].name;
alert(name);
let reader = new FileReader();
reader.onload = function(e) {
// get file content
let text = e.target.result;
let li = document.createElement("li");
li.innerHTML = name + "____" + text;
ul.appendChild(li);
}
reader.readAsText(f,"UTF-8");
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
38976 次 |
| 最近记录: |