בחירת קבצים ואינטראקציה איתם במכשיר המקומי של המשתמש היא אחת מהתכונות הנפוצות ביותר באינטרנט. היא מאפשרת למשתמשים לבחור קבצים ולהעלות אותם לשרת, לדוגמה, כשמשתפים תמונות או שולחים מסמכי מס. הוא גם מאפשר לאתרים לקרוא ולשנות אותם בלי שתצטרכו להעביר את הנתונים ברשת. הדף הזה מסביר איך להשתמש ב-JavaScript כדי לבצע אינטראקציה עם קבצים.
ממשק ה-API המודרני של גישה למערכת קבצים
File System Access API מספק דרך לקריאה ולכתיבה מקבצים ומספריות במערכת המקומית של המשתמש. היא זמינה ברוב הדפדפנים המבוססים על Chromium, כמו Chrome ו-Edge. מידע נוסף זמין במאמר File System Access API.
מכיוון ש-File System Access API לא תואם לכל הדפדפנים, אנחנו ממליצים להשתמש ב-browser-fs-access – ספריית עזרה שמשתמשת ב-API החדש בכל מקום שבו הוא זמין, ומתבססת על הגישה מהדור הקודם במקרים שבהם אין אפשרות כזו.
עובדים עם קבצים, בשיטה הקלאסית
במדריך הזה מוסבר איך לעבוד עם קבצים באמצעות שיטות JavaScript מדור קודם.
בחירת קבצים
יש שתי דרכים עיקריות לבחירת קבצים: באמצעות רכיב קלט ה-HTML, ושימוש באזור גרירה ושחרור.
רכיב קלט HTML
הדרך הקלה ביותר למשתמשים לבחור קבצים היא באמצעות האלמנט <input type="file">
, שנתמך בכל הדפדפנים המובילים. בלחיצה, המשתמש יכול לבחור קובץ או כמה קבצים, אם המאפיין multiple
כלול, באמצעות ממשק המשתמש המובנה של מערכת ההפעלה לבחירת קבצים. כשהמשתמש מסיים לבחור קובץ או קבצים, האירוע 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>
בדוגמה הבאה משתמש יכול לבחור מספר קבצים באמצעות ממשק המשתמש המובנה של מערכת ההפעלה לבחירת קבצים, ואז לרשום במסוף כל קובץ שנבחר.
הגבלה של סוגי הקבצים שהמשתמשים יכולים לבחור
במקרים מסוימים, ייתכן שתרצו להגביל את סוגי הקבצים שהמשתמשים יכולים לבחור. לדוגמה, אפליקציה לעריכת תמונות צריכה לקבל רק תמונות, ולא קובצי טקסט. כדי להגדיר הגבלות על סוגי קבצים, מוסיפים מאפיין accept
לרכיב הקלט כדי לציין את סוגי הקבצים הקבילים:
<input type="file" id="file-selector" accept=".jpg, .jpeg, .png">
גרירה ושחרור בהתאמה אישית
בדפדפנים מסוימים, האלמנט <input type="file">
הוא גם יעד שחרור, שמאפשר למשתמשים לגרור קבצים ולשחרר אותם באפליקציה. עם זאת, יעד השחרור הזה קטן וקשה להשתמש בו. במקום זאת, אחרי שמספקים תכונות ליבה באמצעות אלמנט <input type="file">
, אפשר לספק משטח גדול בהתאמה אישית של גרירה ושחרור.
בחירת אזור השחרור
שטח השחרור תלוי בעיצוב של האפליקציה. יכול להיות שתרצו שרק חלק מהחלון יהיה משטח לשחרור, אבל אפשר להשתמש בכל החלון.
אפליקציית דחיסת התמונות Squoosh מאפשרת למשתמש לגרור תמונה לכל מקום בחלון, וללחוץ על select an image כדי להפעיל את הרכיב <input type="file">
. בכל אפשרות שתבחרו כאזור השחרור, חשוב לוודא שלמשתמשים ברור שהם יכולים לגרור קבצים אל המשטח הזה.
הגדרת תחום השחרור
כדי להפעיל רכיב כאזור גרירה ושחרור, יוצרים מאזינים לשני אירועים: dragover
ו-drop
.
האירוע dragover
מעדכן את ממשק המשתמש של הדפדפן כדי לציין באופן חזותי שפעולת הגרירה והשחרור יוצרת עותק של הקובץ. האירוע 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
.
מעקב אחר ההתקדמות של קריאת קובץ
כשקוראים קבצים גדולים, כדאי לספק חוויית משתמש כלשהי כדי ליידע את המשתמש עד כמה התקדמות הקריאה. לשם כך, צריך להשתמש באירוע progress
שסופק על ידי FileReader
. לאירוע progress
יש שני מאפיינים:
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);
}
תמונה ראשית (Hero) של וינסנט בוטה מתוך UnFlood