วิธีสมัยใหม่
การใช้ File Handling API
ก่อนอื่น ให้ประกาศแอตทริบิวต์ file_handlers
ในไฟล์ Manifest ของเว็บแอป File Handling API กำหนดให้คุณต้องระบุพร็อพเพอร์ตี้ action
(URL ที่ใช้จัดการ) และพร็อพเพอร์ตี้ accept
ซึ่งเป็นออบเจ็กต์ที่มีประเภท MIME เป็นคีย์และอาร์เรย์ของนามสกุลไฟล์ที่เกี่ยวข้องโดยเฉพาะ
{
"file_handlers": [
{
"action": "./",
"accept": {
"image/*": [".jpg", ".jpeg", ".png", ".webp", ".svg"]
}
}
]
}
ขั้นตอนต่อไป คุณต้องใช้ File Handling API เพื่อจัดการไฟล์ที่เปิดอยู่ผ่าน 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.
}
});
}
การสนับสนุนเบราว์เซอร์
- 102
- 102
- x
- x
วิธีคลาสสิก
กำลังใช้เมธอด DataTransferItem.getAsFile()
แบบคลาสสิก
หากระบบไม่รองรับ File Handling API คุณยังคงลากและวางไฟล์จากเครื่องมือสำรวจไฟล์ลงในแอปได้ โดยเมธอด DataTransferItem.getAsFile()
จะแสดงผลออบเจ็กต์ File
ของรายการข้อมูลลาก
หากรายการไม่ใช่ไฟล์ เมธอดนี้จะแสดง null
แม้ว่าจะอ่านไฟล์ได้
แต่จะเขียนกลับไปไม่ได้ วิธีนี้มีข้อเสียเนื่องจากไม่รองรับไดเรกทอรี
การเพิ่มประสิทธิภาพแบบต่อเนื่อง
ข้อมูลโค้ดด้านล่างใช้ File Handling API เมื่อมีให้ใช้ และจะมีการลงทะเบียนตัวควบคุมแบบลากและวางเพิ่มเติมเพื่อให้จัดการไฟล์ที่ลากได้
ประกาศประเภทไฟล์ที่จัดการในไฟล์ Manifest ของเว็บแอปได้ เบราว์เซอร์ที่ไม่รองรับ File Handling API จะไม่สนใจเพียงเบราว์เซอร์นี้
{
"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.
}
}
});
อ่านเพิ่มเติม
- ให้เว็บแอปพลิเคชันที่ติดตั้งไว้เป็นตัวแฮนเดิลไฟล์
- File System Access API: การลดความซับซ้อนในการเข้าถึงไฟล์ในเครื่อง
เดโม
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}
`;
}
});
}