Cách làm hiện đại
Sử dụng File Handling API
Trước tiên, hãy khai báo thuộc tính file_handlers trong tệp kê khai ứng dụng web. File Handling API yêu cầu bạn chỉ định thuộc tính action (URL xử lý) và thuộc tính accept. Đây là một đối tượng có các loại MIME làm khoá và mảng của các tiện ích tệp tương ứng cụ thể.
{
"file_handlers": [
{
"action": "./",
"accept": {
"image/*": [".jpg", ".jpeg", ".png", ".webp", ".svg"]
}
}
]
}
Tiếp theo, bạn cần sử dụng API Xử lý tệp để xử lý bắt buộc các tệp đã mở thông qua launchQueue.
if ('launchQueue' in window && 'files' in LaunchParams.prototype) {
launchQueue.setConsumer((launchParams) => {
if (!launchParams.files.length) {
return;
}
for (const fileHandle of launchParams.files) {
// Handle the file.
}
});
}
Cách cổ điển
Sử dụng phương thức DataTransferItem.getAsFile() cũ
Nếu File Handling API không được hỗ trợ, bạn vẫn có thể kéo và thả tệp từ trình khám phá tệp vào ứng dụng. Phương thức DataTransferItem.getAsFile() sẽ trả về đối tượng File của mục dữ liệu kéo.
Nếu mục không phải là tệp, phương thức này sẽ trả về null. Mặc dù bạn có thể đọc tệp, nhưng không có cách nào để ghi lại vào tệp đó. Phương thức này có nhược điểm là không hỗ trợ thư mục.
Cải tiến tăng dần
Đoạn mã bên dưới sử dụng File Handling API khi có sẵn, đồng thời đăng ký các trình xử lý kéo và thả để có thể xử lý các tệp được kéo.
Khai báo các loại tệp có thể được xử lý trong tệp kê khai ứng dụng web. Những trình duyệt không hỗ trợ File Handling API sẽ bỏ qua yêu cầu này.
{
"file_handlers": [
{
"action": "./",
"accept": {
"image/*": [".jpg", ".jpeg", ".png", ".webp", ".svg"]
}
}
]
}
// File Handling API
const handleLaunchFiles = () => {
window.launchQueue.setConsumer((launchParams) => {
if (!launchParams.files.length) {
return;
}
launchParams.files.forEach(async (handle) => {
const file = await handle.getFile();
console.log(`File: ${file.name}`);
// Do something with the file.
});
});
};
if ('launchQueue' in window && 'files' in LaunchParams.prototype) {
handleLaunchFiles();
}
// This is the drag and drop zone.
const elem = document.querySelector('main');
// Prevent navigation.
elem.addEventListener('dragover', (e) => {
e.preventDefault();
});
// Visually highlight the drop zone.
elem.addEventListener('dragenter', (e) => {
elem.style.outline = 'solid red 1px';
});
// Visually unhighlight the drop zone.
elem.addEventListener('dragleave', (e) => {
elem.style.outline = '';
});
// This is where the drop is handled.
elem.addEventListener('drop', async (e) => {
// Prevent navigation.
e.preventDefault();
// Unhighlight the drop zone.
elem.style.outline = '';
// Prepare an array of promises…
const fileHandlesPromises = [...e.dataTransfer.items]
// …by including only files (where file misleadingly means actual file _or_
// directory)…
.filter((item) => item.kind === 'file')
// …and, depending on previous feature detection…
.map((item) => item.getAsFile());
// Loop over the array of promises.
for await (const handle of fileHandlesPromises) {
// This is where we can actually exclusively act on the files.
if (handle.isFile) {
console.log(`File: ${handle.name}`);
// Do something with the file.
}
}
});
Tài liệu đọc thêm
- Cho phép các ứng dụng web đã cài đặt trở thành trình xử lý tệp
- API Truy cập hệ thống tệp: đơn giản hoá quyền truy cập vào các tệp cục bộ
Bản minh hoạ
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="manifest" href="manifest.json" />
<title>How to handle files opened from the file explorer</title>
<link rel="stylesheet" href="style.css" />
<!-- TODO: Devsite - Removed inline handlers -->
<!-- <script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', async () => {
const registration = await navigator.serviceWorker.register(
'sw.js',
);
console.log(
'Service worker registered for scope',
registration.scope,
);
});
}
</script>
<script src="script.js" type="module"></script> -->
</head>
<body>
<h1>How to handle files opened from the file explorer</h1>
<p>Install the app. After the installation, try opening an image file from the file explorer with the app.
</body>
</html>CSS
html {
box-sizing: border-box;
font-family: system-ui, sans-serif;
color-scheme: dark light;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
margin: 1rem;
}
img {
height: auto;
max-width: 100%;
display: block;
}
JS
if ('launchQueue' in window && 'files' in LaunchParams.prototype) {
launchQueue.setConsumer((launchParams) => {
if (!launchParams.files.length) {
return;
}
for (const fileHandle of launchParams.files) {
document.body.innerHTML += `${fileHandle.name}
`;
}
});
}