问题
我尝试访问 dataTransfer 对象。它在顶级代码中运行良好,但在 Promise.prototype.then() 中返回 undefined。
拖放文件后,结果为LOG#1 = [object DataTransferItem] LOG#2 = undefined
真实代码示例(从实际项目中简化):
function dropHandler(e) {
let fileNameList = [];
let promise = new Promise((resolve, reject) => {
console.log('File(s) dropped');
e.preventDefault();
if (e.dataTransfer.items) {
// Get list of all dropped file name.
for (var i = 0; i < e.dataTransfer.items.length; i++) {
if (e.dataTransfer.items[i].kind === 'file') {
fileNameList.push(e.dataTransfer.items[i].getAsFile().name);
}
}
// Read text from pairs.txt.
let pairsIndex = fileNameList.map(str => str.toLowerCase()).indexOf("pairs.txt");
let pairsFile = e.dataTransfer.items[pairsIndex].getAsFile();
console.log(pairsFile);
console.log("LOG#1 = " + e.dataTransfer.items[0]);
pairsFile.text().then(text => {
console.log("LOG#2 = " + e.dataTransfer.items[0]);
resolve();
});
}
});
promise.finally(() => {
e.dataTransfer.items.clear();
fileNameList = [];
});
}
function dragOverHandler(e) {
console.log('File(s) in drop zone');
// Prevent default behavior (Prevent file from being opened)
e.preventDefault();
}
#drop_zone {
border: 3px dashed;
width: 100%;
height: 300px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h5>Instruction: Drag and drop files to make quiz.</h5>
<div id="drop_zone" ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
<i class="bi bi-file-arrow-up" style="font-size: 10rem; color: rgb(189, 189, 189);"></i>
<p>Drag one or more files to this Drop Zone ...</p>
</div>
</body>
</html>
问题
答案 0 :(得分:1)
调用 .then()
后,您不再位于函数的原始调用堆栈中。这在事件侦听器中尤为重要。
我们可以用 setTimeout 重现同样的效果:
e.preventDefault();
console.log(e.dataTransfer.items);
setTimeout(()=> {
console.log(e.dataTransfer.items);
})
结果:
DataTransferItemList {0: DataTransferItem, 1: DataTransferItem, 2: DataTransferItem, 3: DataTransferItem, length: 4}
DataTransferItemList {length: 0}
因此 DataTransfer
的上下文会随着时间而丢失。一种方法是在丢失之前复制所需的数据并在需要时重新使用它:
const items = [...e.dataTransfer.items];
function dropHandler(e) {
let fileNameList = [];
let promise = new Promise((resolve, reject) => {
console.log('File(s) dropped');
e.preventDefault();
if (e.dataTransfer.items) {
// Get list of all dropped file name.
for (var i = 0; i < e.dataTransfer.items.length; i++) {
if (e.dataTransfer.items[i].kind === 'file') {
fileNameList.push(e.dataTransfer.items[i].getAsFile().name);
}
}
// Read text from pairs.txt.
let pairsIndex = fileNameList.map(str => str.toLowerCase()).indexOf("pairs.txt");
// const items = [...e.dataTransfer.items];
// const pairFiles = items[pairsIndex].getAsFile();
// New code as per comment
const items = [...e.dataTransfer.items].map(item => item.getAsFile());
let pairsFile = items[pairsIndex];
console.log(pairsFile);
console.log("LOG#1 = " + items[0]);
pairsFile.text().then(text => {
console.log("LOG#2 = " + items[0]);
resolve();
});
}
});
promise.finally(() => {
e.dataTransfer.items.clear();
fileNameList = [];
});
}
function dragOverHandler(e) {
console.log('File(s) in drop zone');
// Prevent default behavior (Prevent file from being opened)
e.preventDefault();
}
#drop_zone {
border: 3px dashed;
width: 100%;
height: 300px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h5>Instruction: Drag and drop files to make quiz.</h5>
<div id="drop_zone" ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
<i class="bi bi-file-arrow-up" style="font-size: 10rem; color: rgb(189, 189, 189);"></i>
<p>Drag one or more files to this Drop Zone ...</p>
</div>
</body>
</html>