الحقل file
عناصر <input>
ذات النوع file
تسمح للمستخدم باختيار ملف أو أكثر لرفعها إلى الخادوم أو تعديلها باستخدام الواجهة البرمجية File
.
الخاصية value
تحتوي الخاصية value
في الحقل file
على سلسلة نصية (DOMString
) التي تُمثِّل المسار إلى الملف (أو الملفات) المختارة. بعض الأمور التي عليك أن تضعها بالحسبان:
- إذا تم اختيار عدِّة ملفات، فقيمة الخاصية
value
ستُمثِّل أوّل ملف مختار، لكن يمكن الوصول إلى الملفات الأخرى عبر الخاصيةFileList
في DOM التابعة للعنصر<input>
. - إذا لم يتم اختيار ملف بعد، فستكون قيمة الخاصية
value
فارغةً. - سيتم إسباق السلسلة النصية بالمسار
C:\fakepath\
لمنع البرمجيات الخبيثة من معرفة بنية نظام الملفات عند المستخدم.
استخدام حقل رفع الملفات
حقل رفع ملفات بسيط
<form>
<div>
<label for="file">اختر ملفًا لترفعه</label>
<input type="file" id="file" name="file" multiple>
</div>
<div>
<button>رفع</button>
</div>
</form>
بغض النظر عن جهاز المستخدم أو نظام التشغيل، سيوفِّر هذا الحقل زرًا سيفتح نافذة منتقي الملفات للسماح للمستخدم باختيار ملف.
استخدام الخاصية multiple
-كما في المثال أعلاه- سيُمكِّن المستخدم من اختيار أكثر من ملف معًا، ويمكن للمستخدم اختيار عدِّة ملفات في منتقي الملفات بأي طريقة يسمح بها نظام تشغيله (مثلًا: بالضغط على زر Shift
أو Ctrl
والنقر بالفأرة). إذا كنت تريد أن تسمح للمستخدم باختيار ملف واحد في كل حقل file
فاحذف الخاصية multiple
.
عند إرسال النموذج في المثال السابق، فسيُضاف اسم كل ملف مُختار إلى رابط URL كما يلي: ?file=file1.txt&file=file2.txt
.
الحصول على معلومات عن الملفات المختارة
ستُعاد الملفات المختارة عبر الخاصية HTMLInputElement.files
، التي ستُعيد الكائن FileList
الذي يحتوي على قائمة بكائنات من النوع File
، وسيسلك الكائن FileList
سلوك مصفوفة، أي بإمكاننا استخدام الخاصية length
عليه للحصول على عدد الملفات المختارة.
كل كائن File
يحتوي على المعلومات الآتية:
name
: اسم الملف.lastModified
: رقم يُمثِّل التاريخ الذي عُدِّل فيه الملف آخر مرة على شكل بصمة وقت (Unix timestamp).lastModifiedDate
: كائنDate
يُمثِّل الوقت والتاريخ الذي عُدِّل فيه الملف آخر مرة.size
: رقم يُمثِّل حجم الملف التخزيني مقدرًا بالبايت.type
: سلسلة نصية (DOMString
) تمثِّل نوع MIME للملف.
وضع قيود على أنواع الملفات المسموحة
لن ترغب في أغلبية الأوقات في السماح للمستخدم برفع أيّ نوعٍ يشاء من الملفات، فلو كان حقل رفع الملفات يستخدم لرفع صورة لحساب المستخدم، فربما تريد السماح لأنواع الصور المتوافقة مع الويب مثل JPEG أو PNG فقط.
يمكن تحديد أنواع الملفات التي يقبلها الخادوم باستخدام الخاصية accept
، وبقية الأنواع سيتجاهلها المتصفح، يجب أن تكون قيمة هذه الخاصية هي قائمة مفصولة بفاصلة لمُحدِّدات أنواع الملفات الآتية:
- امتداد الملف الذي يجب أن يبدأ بنقطة (مثل
.jpg
أو .png
أو .doc
). - نوع MIME صحيح
- السلسلة النصية
audio/*
التي تُمثِّل الملفات الصوتية. - السلسلة النصية
video/*
التي تُمثِّل ملفات الفيديو. - السلسلة النصية
image/*
التي تُمثِّل الصور (تسمح العديد من متصفحات الهواتف التقاط الصور عند استخدام هذه القيمة).
هذا مثال عن استخدام حقل رفع الملفات للسماح للمستخدم برفع صورة لحسابه بصيغة JPEG أو PNG:
<form method="post" enctype="multipart/form-data">
<div>
<label for="profile_pic">اختر صورةً لترفعها</label>
<input type="file" id="profile_pic" name="profile_pic"
accept=".jpg, .jpeg, .png">
</div>
<div>
<button>رفع</button>
</div>
</form>
إذا حاولت اختيار ملف في المثال السابق فسترى أنَّ منتقي الملفات لا يسمح لك إلا باختيار أنواع الملفات المُحدَّدة عبر الخاصية accept
(قد يختلف سلوك منتقي الملفات بين المتصفحات وبين أنظمة التشغيل).
لا تتحقق الخاصية accept
من نوع الملفات المُحدَّدة، وإنما توفّر «تلميحةً» للمتصفحات لكي توجِّه المستخدم إلى اختيار نوع الملفات الصحيح، لكن من الممكن (في أغلبية الحالات) أن يتمكن المستخدم من تفعيل خيار في منتقي الملفات لجعل جميع الملفات قابلة للاختيار ومن ثم اختيار نوع ملفات غير صحيح.
وبالتالي علينا أن نحرص على التحقق من نوع الملف بالطرائق المناسبة في جهة الخادوم.
أمثلة
سنُنشِئ في هذا الملف منتقي ملفات متقدم نسبيًا الذي يستفيد من معلومات الملف المتوافرة في خاصية HTMLInputElement.files
، وسنستعرض بعض الحيل المفيدة.
يمكنك النظر إلى الشيفرة الكاملة أو تجربة المثال الحي، لكننا لن نشرح أنماط CSS لأن تركيزنا سيكون على JavaScript.
لننظر أوّلًا إلى شيفرة HTML:
<form>
<div>
<label for="image_uploads">اختر صورًا لترفعها</label>
<input type="file" id="image_uploads" name="image_uploads" accept=".jpg, .jpeg, .png" multiple>
</div>
<div class="preview">
<p>لم تُحدَّد ملفات لترفع بعد</p>
</div>
<div>
<button>رفع</button>
</div>
</form>
الشيفرة السابقة تشبه ما قد سلف، لذا لا حاجة إلى شرحها.
أما في شيفرة JavaScript فحصلنا في أوّل عدِّة أسطر منها على مرجعيات إلى عنصر <input>
وعنصر <div>
ذي الفئة preview
. ثم سنخفي الحقل file
لأنَّ شكله الافتراضي بشع وغير متناسق في جميع المتصفحات، يمكن تفعيل العنصر بالضغط على العنصر <label>
المرتبط معه، لذا من الأفضل -بصريًا- إخفاء الحقل وتنسيق اللافتة الخاصة به لتشبه الزر، لكي يعرف المستخدم أنَّ بإمكانه الضغط عليها إذا أراد رفع الملفات:
var input = document.querySelector('input');
var preview = document.querySelector('.preview');
input.style.opacity = 0;
ملاحظة: استخدمنا الخاصية opacity
لإخفاء حقل رفع الملفات بدلًا من visibility: hidden
أو display: none
لأن التقنيات المساعدة في قابلية الوصول ستُفسِّر آخر خاصيتين على أنهما تجعلان حقل رفع الملفات غير تفاعلي.
ثم سنضيف دالة لمعالجة الأحداث المرتبطة بالحقل عندما يتم تغيير قيمته (أي عندما يختار المستخدم بعض الملفات)، وقوع الحدث change
سيؤدي إلى استدعاء الدالة updateImageDisplay()
التي سنعرفها لاحقًا.
input.addEventListener('change', updateImageDisplay);
عند استدعاء الدالة updateImageDisplay()
فستقوم الشيفرة بما يلي:
- استخدام حلقة
while
لحذف المحتوى السابق لعنصر<div>
الذي يستخدم لعرض مصغرات للصور المرفوعة. - الحصول على الكائن
FileList
الذي يحتوي على معلومات عن جميع الملفات المختارة، وتخزينه في متغير باسمcurFiles
. - التحقق إذا تم اختيار أيّة ملفات، عبر النظر إن كانت قيمة الخاصية
curFile.length
تساوي0
، فإذا كانت كذلك فستُطبَع رسالة إلى عنصر<div>
(الذي يستخدم لعرض المصغرات) تُشير إلى عدم تحديد أيّة ملفات. - إذا تم اختيار ملفات، فسنمر عليها كلها بحلقة تكرار ونطبع معلومات عنها في عنصر
<div>
. - لاحظ أننا نستخدم الدالة
validFileType()
للتأكد أنَّ نوع الملف صحيح (أي أنَّه صورة). - إذا كان نوع الملف صالحًا، فسوف:
- نطبع اسمه وحجمه التخزيني داخل العنصر
<div>
(سنحصل عليهما من الخاصيتينcurFiles[i].name
وcurFiles[i].size
)، الدالةreturnFileSize()
ستُعيد حجم الملف بعد تنسيقه بصيغة مقروءة (مع وضع الواحدة bytes أو KB أو MB) فالمتصفحات تُعيد حجم الملف بواحدة البايت دومًا. - توليد مُصغرات للصور باستدعاء الدالة
window.URL.createObjectURL(curFiles[i])
وتقليل حجم الصورة باستخدام CSS ثم إضافة الصورة في القائمة أيضًا.
- نطبع اسمه وحجمه التخزيني داخل العنصر
- أما إذا كان نوع الملف غير صالح، فسنعرض رسالة ضمن القائمة تخبر المستخدم بأن يختار ملفًا من النوع الصحيح.
function updateImageDisplay() {
while(preview.firstChild) {
preview.removeChild(preview.firstChild);
}
var curFiles = input.files;
if(curFiles.length === 0) {
var para = document.createElement('p');
para.textContent = 'No files currently selected for upload';
preview.appendChild(para);
} else {
var list = document.createElement('ol');
preview.appendChild(list);
for(var i = 0; i < curFiles.length; i++) {
var listItem = document.createElement('li');
var para = document.createElement('p');
if(validFileType(curFiles[i])) {
para.textContent = 'File name ' + curFiles[i].name + ', file size ' + returnFileSize(curFiles[i].size) + '.';
var image = document.createElement('img');
image.src = window.URL.createObjectURL(curFiles[i]);
listItem.appendChild(image);
listItem.appendChild(para);
} else {
para.textContent = 'File name ' + curFiles[i].name + ': Not a valid file type. Update your selection.';
listItem.appendChild(para);
}
list.appendChild(listItem);
}
}
}
الدالة validFileType()
تأخذ الكائن File
كوسيط، ثم ستمر على مصفوفة بأنواع الملفات المسموحة وتتحقق من مطابقة نوع الملف لأحدها، وإن عُثِرَ على مُطابقة فستعيد الدالة القيمة true
وإلا فستُعيد false
.
var fileTypes = [
'image/jpeg',
'image/pjpeg',
'image/png'
]
function validFileType(file) {
for(var i = 0; i < fileTypes.length; i++) {
if(file.type === fileTypes[i]) {
return true;
}
}
return false;
}
تأخذ الدالة returnFileSize()
عددًا (مُقدرًا بالبايت، ومأخوذًا من الخاصية size
) وتحوِّله إلى حجم سهل القراءة:
function returnFileSize(number) {
if(number < 1024) {
return number + 'bytes';
} else if(number > 1024 && number < 1048576) {
return (number/1024).toFixed(1) + 'KB';
} else if(number > 1048576) {
return (number/1048576).toFixed(1) + 'MB';
}
}
دعم المتصفحات
Chrome | Firefox | Edge | Safari | Opera |
---|---|---|---|---|
مدعوم | مدعوم | مدعوم | مدعوم | مدعوم |