การเลือกและโต้ตอบกับไฟล์ในอุปกรณ์ภายในของผู้ใช้เป็นหนึ่งใน ฟีเจอร์ที่นิยมใช้กันมากที่สุดในเว็บ ซึ่งช่วยให้ผู้ใช้เลือกไฟล์และ อัปโหลดไปยังเซิร์ฟเวอร์ เช่น เมื่อแชร์รูปภาพหรือส่งข้อมูลภาษี เอกสาร นอกจากนี้ ยังทำให้เว็บไซต์อ่านและจัดการกับเนื้อหาเหล่านั้นได้โดยไม่ต้อง เพื่อถ่ายโอนข้อมูลไปทั่วเครือข่าย หน้านี้จะแนะนำวิธีการใช้ 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 เว็บแอปสำหรับการบีบอัดรูปภาพ](https://web.dev/static/articles/read-files/image/a-screenshot-squoosh-i-9973c866302e4.png?authuser=2&hl=th)
แอปบีบอัดรูปภาพ Squoosh ช่วยให้ผู้ใช้สามารถลากรูปภาพไปที่ใดก็ได้ลงใน
แล้วคลิกเลือกรูปภาพเพื่อเรียก <input type="file">
สิ่งที่คุณเลือกเป็นโซนสำหรับเผยแพร่ โปรดตรวจสอบว่าผู้ใช้เข้าใจอย่างชัดเจน
เพื่อลากไฟล์ไปวางที่ตำแหน่งนั้นได้
กำหนดโซนที่ลดลง
หากต้องการเปิดใช้องค์ประกอบเป็นโซนแบบลากและวาง ให้สร้าง Listener สำหรับ
2 เหตุการณ์: dragover
และ drop
เหตุการณ์ dragover
จะอัปเดต UI ของเบราว์เซอร์เพื่อให้เห็นภาพว่า
การดำเนินการลากและวางคือการสร้างสำเนาของไฟล์ เหตุการณ์ 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
หากเปิดใช้การลากและวาง ผู้ใช้อาจพยายามลากไดเรกทอรีลงในไดเรกทอรี
Drop Zone เมื่อเหตุการณ์การตกหล่นเริ่มทำงาน จะมีออบเจ็กต์ 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 ข้อมูล
หรือ text:
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