使用此处介绍的方法:
https://stackoverflow.com/a/65938910/3825996
我创建了一个网页,您可以将文件拖放到任何地方,然后就会显示内容。删除后,文件的句柄将存储在indexedDB中,刷新页面时,将再次打开并显示上次删除的文件。
我希望如果我更改文件并重新加载页面,则会显示新内容,但事实并非如此。但是,如果我拖放更改的文件,它将正确显示更改的内容。
在Chrome中,我也做了“清空缓存并硬重新加载”,但它仍然显示旧文件内容。
为什么会出现这种情况?文件句柄是否存储完整的文件?我该怎么做才能刷新后重新加载更改的文件?
代码如下: (不能用作 html 片段)
<html>
<head></head>
<body>
<div id="display"></div>
<script>
// stolen from https://www.npmjs.com/package/idb-keyval
function promisifyRequest(request) {
return new Promise((resolve, reject) => {
request.oncomplete = request.onsuccess = () => resolve(request.result);
request.onabort = request.onerror = () => reject(request.error);
});
}
function createStore(dbName, storeName) {
const request = indexedDB.open(dbName);
request.onupgradeneeded = () => request.result.createObjectStore(storeName);
const dbp = promisifyRequest(request);
return (txMode, callback) => dbp.then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName)));
}
let defaultGetStoreFunc;
function defaultGetStore() {
if (!defaultGetStoreFunc) {
defaultGetStoreFunc = createStore('keyval-store', 'keyval');
}
return defaultGetStoreFunc;
}
function idbLoad(key, customStore = defaultGetStore()) {
return customStore('readonly', (store) => promisifyRequest(store.get(key)));
}
function idbStore(key, value, customStore = defaultGetStore()) {
return customStore('readwrite', (store) => {
store.put(value, key);
return promisifyRequest(store.transaction);
});
}
function makeKey(domElement) {
return 'lastOpened-' + domElement.tagName + "-" + domElement.id;
}
async function handleFile(domElement, file) {
await idbStore(makeKey(domElement), file);
const reader = new FileReader();
reader.onload = function (e) {
domElement.dispatchEvent(
new CustomEvent("handlefilecontent", { detail: e.target.result })
);
};
reader.readAsText(file);
}
function dropHandler(ev) {
ev.preventDefault();
if (ev.dataTransfer.items) {
[...ev.dataTransfer.items].forEach((item, i) => {
if (item.kind === "file") {
const file = item.getAsFile();
handleFile(ev.currentTarget, file);
}
});
} else {
[...ev.dataTransfer.files].forEach((file, i) => {
handleFile(ev.currentTarget, file);
});
}
}
function dragOverHandler(ev) {
ev.preventDefault();
}
async function checkLastOpened(domElement) {
try {
let file = await idbLoad(makeKey(domElement));
if (file) {
handleFile(domElement, file)
}
} catch (error) {
alert(error.name, error.message);
}
}
function dragDropInitialize(domElement, callback) {
domElement.addEventListener("drop", dropHandler)
domElement.addEventListener("dragover", dragOverHandler)
domElement.addEventListener("handlefilecontent", (ev) => { callback(ev.detail) })
checkLastOpened(domElement)
}
dragDropInitialize(document.body, (content) => {
document.getElementById("display").innerHTML = content
})
</script>
</body>
</html>
通过
DataTransferItem
的 getAsFile()
或 DataTransfer
的 files
列表返回的对象是 File
对象,它不等同于文件句柄,而是代表文件本身的数据 - File
在网络平台 API 中基本上只是一个带有名称的 Blob
。
因此,当您调用
idbStore()
传递文件时,您实际上是将文件的 contents 存储到数据库中。当存储发生时,实现将吸收文件的内容并将其存储在数据库中。这就是为什么您在重新加载页面时看不到新数据的原因。