วิธีเปิดไฟล์เดียวหรือหลายไฟล์

การจัดการไฟล์เป็นขั้นตอนหนึ่งที่พบบ่อยที่สุดสำหรับแอปบนเว็บ แต่เดิมนั้น ผู้ใช้ต้องอัปโหลดไฟล์ ทำการเปลี่ยนแปลงบางอย่าง แล้วดาวน์โหลดไฟล์อีกครั้ง จนเกิดเป็นสำเนาในโฟลเดอร์ดาวน์โหลด เมื่อใช้ File System Access API ผู้ใช้จะเปิดไฟล์ได้โดยตรง ทำการแก้ไข และบันทึกการเปลี่ยนแปลงในไฟล์ต้นฉบับได้

หากต้องการเปิดไฟล์ ให้ไปที่ showOpenFilePicker() ซึ่งจะส่งคืนคำมั่นสัญญาพร้อมกับอาร์เรย์ของไฟล์ที่เลือก หากต้องการหลายไฟล์ ให้ส่ง { multiple: true, } ไปยังเมธอด

การสนับสนุนเบราว์เซอร์

  • 86
  • 86
  • x
  • x

แหล่งที่มา

วิธีคลาสสิก

การใช้องค์ประกอบ <input type="file">

องค์ประกอบ <input type="file"> ในหน้าเว็บช่วยให้ผู้ใช้คลิกและเปิดไฟล์ได้อย่างน้อย 1 ไฟล์ เคล็ดลับตอนนี้ประกอบด้วยการแทรกองค์ประกอบในหน้าด้วย JavaScript โดยไม่สามารถมองเห็นได้และคลิกเนื้อหานั้นแบบเป็นโปรแกรม

การสนับสนุนเบราว์เซอร์

  • 1
  • 12
  • 1
  • 1

แหล่งที่มา

การเพิ่มประสิทธิภาพแบบต่อเนื่อง

วิธีการด้านล่างใช้ File System Access API เมื่อมีการรองรับและเมื่อเปลี่ยนมาใช้วิธีคลาสสิกแล้ว ในทั้ง 2 กรณี ฟังก์ชันจะแสดงผลอาร์เรย์ของไฟล์ แต่ในกรณีที่มีการรองรับ File System Access API ออบเจ็กต์ไฟล์แต่ละรายการจะมี FileSystemFileHandle จัดเก็บไว้ในพร็อพเพอร์ตี้ handle ด้วย คุณจึงเลือกทำให้แฮนเดิลเป็นอนุกรมได้

const openFileOrFiles = async (multiple = false) => {
 
// Feature detection. The API needs to be supported
 
// and the app not run in an iframe.
 
const supportsFileSystemAccess =
   
"showOpenFilePicker" in window &&
   
(() => {
     
try {
       
return window.self === window.top;
     
} catch {
       
return false;
     
}
   
})();
 
// If the File System Access API is supported…
 
if (supportsFileSystemAccess) {
    let fileOrFiles
= undefined;
   
try {
     
// Show the file picker, optionally allowing multiple files.
     
const handles = await showOpenFilePicker({ multiple });
     
// Only one file is requested.
     
if (!multiple) {
       
// Add the `FileSystemFileHandle` as `.handle`.
        fileOrFiles
= await handles[0].getFile();
        fileOrFiles
.handle = handles[0];
     
} else {
        fileOrFiles
= await Promise.all(
          handles
.map(async (handle) => {
           
const file = await handle.getFile();
           
// Add the `FileSystemFileHandle` as `.handle`.
            file
.handle = handle;
           
return file;
         
})
       
);
     
}
   
} catch (err) {
     
// Fail silently if the user has simply canceled the dialog.
     
if (err.name !== 'AbortError') {
        console
.error(err.name, err.message);
     
}
   
}
   
return fileOrFiles;
 
}
 
// Fallback if the File System Access API is not supported.
 
return new Promise((resolve) => {
   
// Append a new `<input type="file" multiple? />` and hide it.
   
const input = document.createElement('input');
    input
.style.display = 'none';
    input
.type = 'file';
    document
.body.append(input);
   
if (multiple) {
      input
.multiple = true;
   
}
   
// The `change` event fires when the user interacts with the dialog.
    input
.addEventListener('change', () => {
     
// Remove the `<input type="file" multiple? />` again from the DOM.
      input
.remove();
     
// If no files were selected, return.
     
if (!input.files) {
       
return;
     
}
     
// Return all files or just one file.
      resolve
(multiple ? Array.from(input.files) : input.files[0]);
   
});
   
// Show the picker.
   
if ('showPicker' in HTMLInputElement.prototype) {
      input
.showPicker();
   
} else {
      input
.click();
   
}
 
});
};

อ่านเพิ่มเติม

เดโม

<!DOCTYPE html>
<html lang="en">
 
<head>
   
<meta charset="utf-8" />
   
<meta name="viewport" content="width=device-width, initial-scale=1" />
    <link
      rel="icon"
      href="data:image/svg+xml,
<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📂</text></svg>"
    />
   
<title>How to open one or multiple files</title>
 
</head>
 
<body>
   
<h1>How to open one or multiple files</h1>
   
<button type="button">Open file</button>
   
<button class="multiple" type="button">Open files</button>
   
<pre></pre>
 
</body>
</html>

       
:root {
 
color-scheme: dark light;
}

html
{
 
box-sizing: border-box;
}

*,
*:before,
*:after {
 
box-sizing: inherit;
}

body
{
 
margin: 1rem;
 
font-family: system-ui, sans-serif;
}

button
{
 
margin: 1rem;
}
       

       
const button = document.querySelector('button');
const buttonMultiple = document.querySelector('button.multiple');
const pre = document.querySelector('pre');

const openFileOrFiles = async (multiple = false) => {
 
// Feature detection. The API needs to be supported
 
// and the app not run in an iframe.
 
const supportsFileSystemAccess =
   
"showOpenFilePicker" in window &&
   
(() => {
     
try {
       
return window.self === window.top;
     
} catch {
       
return false;
     
}
   
})();

 
// If the File System Access API is supported…
 
if (supportsFileSystemAccess) {
    let fileOrFiles
= undefined;
   
try {
     
// Show the file picker, optionally allowing multiple files.
      fileOrFiles
= await showOpenFilePicker({ multiple });
     
if (!multiple) {
       
// Only one file is requested.
        fileOrFiles
= fileOrFiles[0];
     
}
   
} catch (err) {
     
// Fail silently if the user has simply canceled the dialog.
     
if (err.name !== 'AbortError') {
        console
.error(err.name, err.message);
     
}
   
}
   
return fileOrFiles;
 
}
 
// Fallback if the File System Access API is not supported.
 
return new Promise((resolve) => {
   
// Append a new `` and hide it.
   
const input = document.createElement('input');
    input
.style.display = 'none';
    input
.type = 'file';
    document
.body.append(input);
   
if (multiple) {
      input
.multiple = true;
   
}
   
// The `change` event fires when the user interacts with the dialog.
    input
.addEventListener('change', () => {
     
// Remove the `` again from the DOM.
      input
.remove();
     
// If no files were selected, return.
     
if (!input.files) {
       
return;
     
}
     
// Return all files or just one file.
      resolve
(multiple ? input.files : input.files[0]);
   
});
   
// Show the picker.
   
if ('showPicker' in HTMLInputElement.prototype) {
      input
.showPicker();
   
} else {
      input
.click();
   
}
 
});
};

button
.addEventListener('click', async () => {
 
const file = await openFileOrFiles();
 
if (!file) {
   
return;
 
}
  pre
.textContent += `${file.name}\n`;
});

buttonMultiple
.addEventListener('click', async () => {
 
const files = await openFileOrFiles(true);
 
if (!files) {
   
return;
 
}
 
Array.from(files).forEach((file) => (pre.textContent += `${file.name}\n`));
});