การเลือกและโต้ตอบกับไฟล์ในอุปกรณ์ของผู้ใช้เป็นหนึ่งในฟีเจอร์ของเว็บที่ใช้กันมากที่สุด ซึ่งช่วยให้ผู้ใช้เลือกไฟล์และ อัปโหลดไปยังเซิร์ฟเวอร์ได้ เช่น เมื่อแชร์รูปภาพหรือส่งเอกสารภาษี นอกจากนี้ยังช่วยให้เว็บไซต์อ่านและจัดการข้อมูลได้โดยไม่ต้อง โอนข้อมูลผ่านเครือข่าย หน้านี้จะอธิบายวิธีใช้ JavaScript เพื่อโต้ตอบกับไฟล์
File System Access API ที่ทันสมัย
File System Access API มีวิธีอ่านและเขียนไฟล์และ ไดเรกทอรีในระบบของผู้ใช้ ฟีเจอร์นี้พร้อมใช้งานในเบราว์เซอร์ที่พัฒนาบน Chromium ส่วนใหญ่ เช่น Chrome และ Edge ดูข้อมูลเพิ่มเติมได้ที่File System Access API
เนื่องจาก File System Access API ไม่สามารถใช้ร่วมกับเบราว์เซอร์บางตัวได้ เราจึง ขอแนะนำให้ใช้ browser-fs-access ซึ่งเป็นไลบรารีตัวช่วยที่ใช้ API ใหม่ทุกครั้งที่พร้อมใช้งาน และ กลับไปใช้แนวทางเดิมเมื่อไม่พร้อมใช้งาน
ทำงานกับไฟล์ในรูปแบบคลาสสิก
คู่มือนี้จะแสดงวิธีโต้ตอบกับไฟล์โดยใช้วิธี JavaScript เดิม
เลือกไฟล์
การเลือกไฟล์มี 2 วิธีหลักๆ ได้แก่ การใช้องค์ประกอบอินพุต HTML และการใช้โซนลากและวาง
องค์ประกอบอินพุต HTML
วิธีที่ง่ายที่สุดสำหรับผู้ใช้ในการเลือกไฟล์คือการใช้องค์ประกอบ
<input type="file">
ซึ่งรองรับในเบราว์เซอร์หลักทุกเบราว์เซอร์ เมื่อคลิกแล้ว จะช่วยให้ผู้ใช้
เลือกไฟล์ หรือหลายไฟล์หากมีแอตทริบิวต์
multiple
รวมอยู่ด้วย โดยใช้ UI การเลือกไฟล์ในตัวของระบบปฏิบัติการ เมื่อผู้ใช้เลือกไฟล์เสร็จแล้ว change
เหตุการณ์ขององค์ประกอบจะเริ่มทำงาน คุณเข้าถึงรายการไฟล์ได้จาก event.target.files
ซึ่งเป็นออบเจ็กต์ FileList
แต่ละรายการใน FileList
คือออบเจ็กต์ File
<!-- The `multiple` attribute lets users select multiple files. -->
<input type="file" id="file-selector" multiple>
<script>
const fileSelector = document.getElementById('file-selector');
fileSelector.addEventListener('change', (event) => {
const fileList = event.target.files;
console.log(fileList);
});
</script>
ตัวอย่างต่อไปนี้ช่วยให้ผู้ใช้เลือกหลายไฟล์ได้โดยใช้ UI การเลือกไฟล์ในตัวของระบบปฏิบัติการ จากนั้นจะบันทึกแต่ละไฟล์ที่เลือกไว้ในคอนโซล
จำกัดประเภทไฟล์ที่ผู้ใช้เลือกได้
ในบางกรณี คุณอาจต้องการจำกัดประเภทไฟล์ที่ผู้ใช้เลือกได้ เช่น แอปแต่งรูปภาพควรรับเฉพาะรูปภาพ ไม่ใช่ไฟล์ข้อความ หากต้องการตั้งค่า
ข้อจำกัดของประเภทไฟล์ ให้เพิ่มแอตทริบิวต์
accept
ลงในองค์ประกอบอินพุตเพื่อระบุประเภทไฟล์ที่ยอมรับ
<input type="file" id="file-selector" accept=".jpg, .jpeg, .png">
การลากและวางที่กำหนดเอง
ในบางเบราว์เซอร์ องค์ประกอบ <input type="file">
ยังเป็นเป้าหมายการวางด้วย
ซึ่งอนุญาตให้ผู้ใช้ลากและวางไฟล์ลงในแอปของคุณได้ อย่างไรก็ตาม เป้าหมายการวางนี้
มีขนาดเล็กและอาจใช้งานยาก แต่หลังจากระบุฟีเจอร์หลักโดยใช้
องค์ประกอบ <input type="file">
แล้ว คุณจะระบุพื้นผิวการลากและวางที่กำหนดเองขนาดใหญ่ได้
เลือกจุดส่ง
พื้นผิวการวางจะขึ้นอยู่กับการออกแบบแอปพลิเคชัน คุณอาจต้องการให้ เฉพาะบางส่วนของหน้าต่างเป็นพื้นผิวการวาง แต่คุณสามารถใช้ทั้งหน้าต่างได้

แอปบีบอัดรูปภาพ Squoosh ช่วยให้ผู้ใช้ลากรูปภาพไปยังที่ใดก็ได้ในหน้าต่าง และคลิกเลือกรูปภาพเพื่อเรียกใช้องค์ประกอบ <input type="file">
ไม่ว่าคุณจะเลือกอะไรเป็นโซนวาง โปรดตรวจสอบว่าผู้ใช้เข้าใจว่าสามารถลากไฟล์ไปยังพื้นผิวนั้นได้
กำหนดโซนวาง
หากต้องการเปิดใช้องค์ประกอบเป็นโซนลากและวาง ให้สร้าง Listener สำหรับ
เหตุการณ์ 2 รายการ ได้แก่ dragover
และ drop
dragover
event updates the browser UI to visually indicate that the
drag-and-drop action is creating a copy of the file. drop
เหตุการณ์จะทริกเกอร์
หลังจากที่ผู้ใช้วางไฟล์ลงในพื้นผิว เช่นเดียวกับองค์ประกอบอินพุต คุณสามารถเข้าถึงรายการไฟล์จาก event.dataTransfer.files
ซึ่งเป็นออบเจ็กต์ FileList
แต่ละรายการใน FileList
คือออบเจ็กต์ File
const dropArea = document.getElementById('drop-area');
dropArea.addEventListener('dragover', (event) => {
event.stopPropagation();
event.preventDefault();
// Style the drag-and-drop as a "copy file" operation.
event.dataTransfer.dropEffect = 'copy';
});
dropArea.addEventListener('drop', (event) => {
event.stopPropagation();
event.preventDefault();
const fileList = event.dataTransfer.files;
console.log(fileList);
});
event.stopPropagation()
และ event.preventDefault()
จะหยุดลักษณะการทำงานเริ่มต้นของเบราว์เซอร์และให้โค้ดของคุณทำงานแทน หากไม่มีฟังก์ชันนี้
เบราว์เซอร์จะออกจากหน้าเว็บของคุณและเปิดไฟล์
ที่ผู้ใช้วางลงในหน้าต่างเบราว์เซอร์
ดูการสาธิตแบบสดได้ที่การลากและวางที่กำหนดเอง
แล้วไดเรกทอรีล่ะ
ขออภัย ปัจจุบันยังไม่มีวิธีที่ดีในการเข้าถึงไดเรกทอรีโดยใช้ JavaScript
แอตทริบิวต์ webkitdirectory
ในองค์ประกอบ <input type="file">
ช่วยให้ผู้ใช้เลือกไดเรกทอรี
หรือไดเรกทอรีต่างๆ ได้ รองรับในเบราว์เซอร์หลักส่วนใหญ่
ยกเว้น Firefox สำหรับ Android และ Safari ใน iOS
หากเปิดใช้การลากและวาง ผู้ใช้อาจพยายามลากไดเรกทอรีไปยัง
โซนวาง เมื่อเหตุการณ์การวางทริกเกอร์ จะมีออบเจ็กต์ File
สำหรับ
ไดเรกทอรี แต่จะไม่มีสิทธิ์เข้าถึงไฟล์ใดๆ ในไดเรกทอรี
อ่านข้อมูลเมตาของไฟล์
ออบเจ็กต์ File
มีข้อมูลเมตาเกี่ยวกับไฟล์ เบราว์เซอร์ส่วนใหญ่
จะระบุชื่อไฟล์ ขนาดของไฟล์ และประเภท MIME แต่เบราว์เซอร์
ต่างๆ อาจให้ข้อมูลที่แตกต่างกันหรือเพิ่มเติม
ขึ้นอยู่กับแพลตฟอร์ม
function getMetadataForFileList(fileList) {
for (const file of fileList) {
// Not supported in Safari for iOS.
const name = file.name ? file.name : 'NOT SUPPORTED';
// Not supported in Firefox for Android or Opera for Android.
const type = file.type ? file.type : 'NOT SUPPORTED';
// Unknown cross-browser support.
const size = file.size ? file.size : 'NOT SUPPORTED';
console.log({file, name, type, size});
}
}
คุณดูการทำงานนี้ได้ในinput-type-file
การสาธิต
อ่านเนื้อหาของไฟล์
ใช้ FileReader
เพื่อ
อ่านเนื้อหาของออบเจ็กต์ File
ลงในหน่วยความจำ คุณบอก FileReader
ให้
อ่านไฟล์เป็นบัฟเฟอร์อาร์เรย์
URL ข้อมูล
หรือข้อความได้โดยทำดังนี้
function readImage(file) {
// Check if the file is an image.
if (file.type && !file.type.startsWith('image/')) {
console.log('File is not an image.', file.type, file);
return;
}
const reader = new FileReader();
reader.addEventListener('load', (event) => {
img.src = event.target.result;
});
reader.readAsDataURL(file);
}
ตัวอย่างนี้จะอ่าน File
ที่ผู้ใช้ระบุ จากนั้นจะแปลงเป็น URL ข้อมูล และใช้ URL ข้อมูลนั้นเพื่อแสดงรูปภาพในองค์ประกอบ img
ดูวิธีตรวจสอบว่าผู้ใช้เลือกไฟล์รูปภาพแล้วได้ที่เดโม
read-image-file
ตรวจสอบความคืบหน้าของการอ่านไฟล์
เมื่ออ่านไฟล์ขนาดใหญ่ การแสดง UX บางอย่างเพื่อบอกผู้ใช้ว่าอ่านไปถึงไหนแล้วอาจเป็นประโยชน์
โดยให้ใช้เหตุการณ์
progress
ที่ FileReader
จัดให้ เหตุการณ์ progress
มีพร็อพเพอร์ตี้ 2 รายการ ได้แก่
loaded
(จำนวนที่อ่าน) และ total
(จำนวนที่ต้องอ่าน)
function readFile(file) {
const reader = new FileReader();
reader.addEventListener('load', (event) => {
const result = event.target.result;
// Do something with result
});
reader.addEventListener('progress', (event) => {
if (event.loaded && event.total) {
const percent = (event.loaded / event.total) * 100;
console.log(`Progress: ${Math.round(percent)}`);
}
});
reader.readAsDataURL(file);
}
รูปภาพหลักโดย Vincent Botta จาก Unsplash