Phong cách hiện đại
Sử dụng API xử lý tệp
Trước tiên, hãy khai báo thuộc tính file_handlers
trong tệp kê khai ứng dụng web. API Xử lý tệp 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ó loại MIME dưới dạng khoá và mảng của đuôi tệp cụ thể tương ứng.
{
"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.
}
});
}
Hỗ trợ trình duyệt
- 102
- 102
- lần
- lần
Cách cổ điển
Sử dụng phương thức DataTransferItem.getAsFile()
cổ điển
Nếu API Xử lý tệp 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()
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ợ các thư mục.
Nâng cao dần dần
Đoạn mã dưới đây sử dụng API xử lý tệp khi có sẵn, đồng thời đăng ký thêm các trình xử lý kéo và thả để có thể xử lý các tệp đã kéo.
Khai báo các loại tệp có thể xử lý trong tệp kê khai ứng dụng web. Những trình duyệt không hỗ trợ API xử lý tệp sẽ bỏ qua thông báo 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 làm 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 tệp cục bộ
Bản minh họa
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}
`;
}
});
}