Việc chọn và tương tác với các tệp trên thiết bị cục bộ của người dùng là một trong những việc các tính năng thường dùng nhất của web. Chế độ này cho phép người dùng chọn tệp và hãy tải chúng lên máy chủ, ví dụ: khi chia sẻ ảnh hoặc gửi thông tin thuế tài liệu. AI của Google cũng cho phép các trang web đọc và thao tác chúng mà không cần để chuyển dữ liệu qua mạng. Trang này hướng dẫn cách sử dụng JavaScript để tương tác với các tệp.
API Truy cập hệ thống tệp hiện đại
API Truy cập hệ thống tệp cung cấp cách thức để đọc và ghi vào tệp và trên hệ thống cục bộ của người dùng. Tính năng này hoạt động trong hầu hết các phiên bản dựa trên Chromium các trình duyệt như Chrome và Edge. Để tìm hiểu thêm về vấn đề này, hãy tham khảo API Truy cập hệ thống tệp.
Do API Truy cập hệ thống tệp không tương thích với tất cả các trình duyệt, nên chúng tôi khuyên bạn nên sử dụng browser-fs-access một thư viện trợ giúp sử dụng API mới bất cứ khi nào có sẵn và phù hợp quay lại phương pháp tiếp cận cũ nếu thực tế không phải vậy.
Làm việc với tệp theo cách cổ điển
Hướng dẫn này cho bạn biết cách tương tác với các tệp bằng các phương thức JavaScript cũ.
Chọn tệp
Có hai cách chính để chọn tệp: sử dụng phần tử đầu vào HTML và sử dụng vùng kéo và thả.
Phần tử nhập HTML
Cách dễ nhất để người dùng chọn tệp là sử dụng
<input type="file">
được hỗ trợ trong mọi trình duyệt chính. Khi nhấp vào, người dùng
chọn một hoặc nhiều tệp nếu
multiple
được bao gồm, bằng cách sử dụng lựa chọn tệp tích hợp sẵn của hệ điều hành
Giao diện người dùng. Khi người dùng chọn xong một hoặc nhiều tệp, change
của phần tử
kích hoạt sự kiện. Bạn có thể truy cập vào danh sách các tệp trong event.target.files
là đối tượng FileList
.
Mỗi mục trong FileList
là một đối tượng 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>
Ví dụ sau đây cho phép người dùng chọn nhiều tệp bằng giao diện người dùng chọn tệp tích hợp sẵn của hệ thống, sau đó ghi nhật ký từng tệp đã chọn vào Google Play.
Giới hạn các loại tệp mà người dùng có thể chọn
Trong một số trường hợp, bạn có thể muốn giới hạn các loại tệp mà người dùng có thể chọn. Cho
ví dụ: ứng dụng chỉnh sửa hình ảnh chỉ nên chấp nhận hình ảnh chứ không chấp nhận tệp văn bản. Để đặt
hãy thêm các quy tắc hạn chế về loại tệp
accept
cho phần tử đầu vào để chỉ định loại tệp được chấp nhận:
<input type="file" id="file-selector" accept=".jpg, .jpeg, .png">
Kéo và thả tuỳ chỉnh
Trong một số trình duyệt, phần tử <input type="file">
cũng là mục tiêu thả.
cho phép người dùng kéo và thả tệp vào ứng dụng của bạn. Tuy nhiên, mục tiêu giảm này
nhỏ và có thể khó sử dụng. Thay vào đó, sau khi bạn cung cấp các tính năng cốt lõi bằng
phần tử <input type="file">
, bạn có thể cung cấp thao tác kéo và thả lớn, tuỳ chỉnh
nền tảng.
Chọn vùng thả của bạn
Nền tảng thả phụ thuộc vào thiết kế của ứng dụng. Có thể bạn chỉ muốn của cửa sổ làm giao diện thả, nhưng bạn có thể sử dụng toàn bộ cửa sổ.
Ứng dụng nén hình ảnh Squoosh cho phép người dùng kéo hình ảnh vào bất cứ đâu vào
cửa sổ và nhấp vào chọn một hình ảnh để gọi <input type="file">
. Bất kể bạn chọn vùng hiển thị như thế nào, hãy đảm bảo người dùng hiểu rõ nội dung
để họ có thể kéo tệp lên bề mặt đó.
Xác định vùng thả
Để bật một phần tử làm vùng kéo và thả, hãy tạo trình nghe cho
hai sự kiện: dragover
và drop
.
Sự kiện dragover
sẽ cập nhật giao diện người dùng của trình duyệt để cho thấy rằng
thao tác kéo và thả là tạo bản sao của tệp. Sự kiện drop
sẽ kích hoạt
sau khi người dùng thả tệp xuống nền tảng. Giống như phần tử đầu vào, bạn
có thể truy cập vào danh sách các tệp từ event.dataTransfer.files
, đây là
Đối tượng FileList
. Một
mục trong FileList
là đối tượng 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()
và event.preventDefault()
dừng hành vi mặc định của trình duyệt và để mã của bạn chạy thay thế. Nếu không có chúng,
trình duyệt sẽ điều hướng khỏi trang của bạn và mở các tệp
người dùng thả vào cửa sổ trình duyệt.
Để xem bản minh hoạ trực tiếp, hãy tham khảo bài viết Kéo và thả tuỳ chỉnh.
Thư mục thì sao?
Rất tiếc, không có cách hay để truy cập vào thư mục bằng JavaScript.
webkitdirectory
trên phần tử <input type="file">
cho phép người dùng chọn một thư mục
hoặc thư mục. Trình duyệt này được hỗ trợ trong hầu hết các trình duyệt chính
ngoại trừ Firefox cho Android và Safari trên iOS.
Nếu bạn bật tính năng kéo và thả, người dùng có thể cố gắng kéo một thư mục vào
vùng thả. Khi sự kiện thả kích hoạt, sự kiện này sẽ bao gồm một đối tượng File
cho giá trị
nhưng không cấp quyền truy cập vào bất kỳ tệp nào trong thư mục đó.
Đọc siêu dữ liệu tệp
Đối tượng File
chứa siêu dữ liệu về tệp đó. Hầu hết trình duyệt
cung cấp tên tệp, kích thước của tệp và loại MIME, mặc dù tuỳ thuộc vào
trên nền tảng, các trình duyệt khác nhau có thể cung cấp các
của bạn.
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});
}
}
Bạn có thể xem ví dụ thực tế trong input-type-file
bản minh hoạ.
Đọc nội dung của tệp
Sử dụng FileReader
để
đọc nội dung của đối tượng File
vào bộ nhớ. Bạn có thể yêu cầu FileReader
đọc tệp dưới dạng vùng đệm mảng,
một URL dữ liệu,
hoặc văn bản:
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);
}
Ví dụ này đọc một File
do người dùng cung cấp, sau đó chuyển đổi nó thành một dữ liệu
URL rồi sử dụng URL dữ liệu đó để hiển thị hình ảnh trong phần tử img
.
Để tìm hiểu cách xác minh rằng người dùng đã chọn một tệp hình ảnh, hãy tham khảo
Bản minh hoạ read-image-file
.
Theo dõi tiến trình đọc tệp
Khi đọc các tệp lớn, việc cung cấp một số trải nghiệm người dùng để cho người dùng biết có thể rất hữu ích
tiến trình đọc đến đâu. Để làm được điều đó, hãy sử dụng
progress
sự kiện do FileReader
cung cấp. Sự kiện progress
có 2 thuộc tính:
loaded
(lượng cần đọc) và total
(lượng cần đọc).
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);
}
Hình ảnh chính của Vincent B lui trên Unsplash