Gần đây, tôi đang thực hiện một dự án phụ, dựa trên việc đọc và thao tác với các tệp để tạo hình thu nhỏ tùy chỉnh cho quay số nhanh của trình duyệt Vivaldi. Tôi đã có thể thực hiện tất cả trong trình duyệt mà không cần xử lý phía máy chủ và tôi muốn chia sẻ với bạn mọi thứ mà tôi đã học được
Hướng dẫn này bao gồm
- sử dụng objectURL và FileReader để đọc tệp từ hệ thống tệp của người dùng
- lấy thông tin của một tập tin như. kích thước, loại và nhiều hơn nữa
- hiển thị bản xem trước của các tệp hình ảnh đã chọn
- xử lý lỗi và trạng thái tải
- BẢNG XẾP HẠNG Ở CUỐI
Để cho phép người dùng của bạn chọn một tệp từ thiết bị của họ, trước tiên bạn phải tạo một input
với loại tệp
Để thực sự lấy các tệp từ đầu vào này, bạn sẽ cần truy cập thuộc tính files
của phần tử đầu vào. Tốt nhất là làm điều đó bằng cách đăng ký một trình lắng nghe sự kiện thay đổi trên phần tử đầu vào. Bằng cách này, một chức năng gọi lại sẽ được gọi mỗi khi người dùng chọn một tệp
Cách bạn làm điều đó sẽ phụ thuộc vào khuôn khổ bạn đang sử dụng. Để làm cho hướng dẫn này được áp dụng rộng rãi nhất có thể, chúng tôi sẽ sử dụng vanilla JS
Kết quả selectFile là một đối tượng File
Thuộc tính của tập tin
Đầu vào tệp cung cấp cho chúng tôi File
đối tượng, vì vậy ngoài nội dung của tệp, chúng tôi có quyền truy cập vào một số thông tin bổ sung, chẳng hạn như
name
- tên tệp, bao gồm cả phần mở rộng nhưng không có đường dẫn [e. g. "cat_photo. png"]size
- kích thước của tệp tính bằng byte. Để có được kích thước ở định dạng dễ đọc hơn của con người, bạn có thể sử dụng thư viện như kích thước tệp hoặc byte. Đối với các trường hợp sử dụng đơn giản, bạn thậm chí có thể viết logic chuyển đổi của riêng mìnhtype
- loại MIME của tệp [e. g. "văn bản/đơn giản", "hình ảnh/png"]lastModified
- ngày sửa đổi cuối cùng của tệp, được biểu thị bằng số mili giây kể từ Kỷ nguyên Unix [01/01/1970 lúc nửa đêm]. Bạn có thể sử dụng hàm tạo Ngày để chuyển đổi dấu thời gian này thành đối tượngDate
javascript hữu ích hơn
File
s cũng có hai thuộc tính khác. files
0 và files
1, cái đầu tiên không được dùng nữa và cái còn lại không chuẩn, vì vậy có lẽ bạn nên tránh sử dụng chúng. Hãy nhớ rằng tất cả các thuộc tính này là chỉ đọc
Tập tin và đốm màu
Ngoài File
, javascript còn có một cách khác để biểu diễn các tệp, được gọi là files
3
files
3 chứa dữ liệu của tệp chung, cùng với thông tin về kích thước và loại tệp. File
thực ra chỉ là một files
3 chuyên biệt hơn, được sử dụng để biểu thị các tệp cụ thể trong hệ thống tệp của người dùng. Nó kế thừa tất cả các phương thức và thuộc tính của Blob, đồng thời chứa một số thông tin bổ sung về tên tệp và ngày sửa đổi lần cuối
Hai cái này về cơ bản có thể hoán đổi cho nhau và bạn có thể sử dụng cái này ở hầu hết mọi nơi bạn có thể sử dụng cái kia. Tuy nhiên, nếu bạn thực sự cần chuyển đổi chúng, bạn có thể làm như vậy bằng cách sử dụng hàm tạo của loại khác
Đọc nội dung của tập tin
Được rồi, vậy là chúng ta đã biết cách chọn và lấy thông tin về các tệp, nhưng làm cách nào để chúng ta thực sự đọc nội dung bên trong chúng? . Đối với mục đích của bài viết này, chúng tôi sẽ chỉ tập trung vào các tệp hình ảnh và văn bản
Phương pháp linh hoạt và được hỗ trợ tốt nhất để đọc nội dung của tệp là API FileReader. Đó là một API hướng sự kiện, vì vậy thay vì chỉ gọi một hàm và lấy nội dung của tệp, chúng ta phải thực hiện thêm một số bước
Hãy bắt đầu với việc đọc một tệp văn bản
- Trước tiên, chúng tôi lấy phần tử đầu vào tệp và đăng ký trình xử lý sự kiện thay đổi trên phần tử đó bằng cách gán hàm gọi lại cho thuộc tính
files
7 của nó - Chúng tôi nhận được tập tin đã chọn
- Chúng tôi kiểm tra xem một tệp có thực sự được chọn hay không và nếu không, [điều này có thể xảy ra chẳng hạn nếu người dùng nhấp vào 'hủy' trong cửa sổ lựa chọn], chúng tôi sẽ thoát khỏi chức năng
- Tiếp theo, chúng tôi tạo một phiên bản của FileReader
- Sau đó, chúng tôi đăng ký bất kỳ trình xử lý sự kiện nào mà chúng tôi có thể cần. Để truy cập nội dung tệp, chúng tôi chỉ thực sự cần sự kiện tải, sự kiện này sẽ kích hoạt khi thao tác đọc kết thúc thành công. Tuy nhiên, bạn cũng nên đăng ký một trình xử lý lỗi. Dưới đây là danh sách đầy đủ các sự kiện có thể xảy ra trong bài viết, cùng với một số mẹo xử lý lỗi, vì vậy hãy tiếp tục đọc 😉
- Sau khi tất cả các trình xử lý sự kiện được đăng ký, chúng tôi bắt đầu thao tác đọc bằng cách gọi một trong các phương thức readAs, trong trường hợp này là
files
8 - Sau khi thao tác đọc kết thúc, nội dung tệp sẽ có sẵn trong thuộc tính
files
9 mà chúng ta có thể truy cập bên trong trình xử lý sự kiện tải [hàm gọi lạiFile
0]
Mẹo nhanh. Bạn có thể truy cập trình đọc bên trong trình xử lý sự kiện theo nhiều cách. File
1. Hãy nhớ rằng File
2 không có sẵn trong arrow functions
Xử lý lỗi
Trong trường hợp có lỗi, trình xử lý sự kiện lỗi được gọi và bạn có thể tìm thấy đối tượng Lỗi trong File
3. Mã lỗi có thể là
File
4 - không tìm thấy tệpFile
5 - không thể đọc tệpFile
6 - đã xảy ra sự cố bảo mậtFile
7 - bị ném khiFile
8 được gọi trong khi không có thao tác đọc nào đang diễn ra
Hầu hết thời gian không cần phân biệt giữa các loại lỗi này, có thể ngoại trừ File
9 nói chung là vô hại và có thể bỏ qua
Trạng thái sẵn sàng
Thao tác đọc không đồng bộ, vì vậy đừng thử truy cập vào files
9 ngay sau lệnh gọi readAs. Nếu bạn thực sự cần kiểm tra giá trị files
9 bên ngoài trình xử lý sự kiện tải, trước tiên hãy đảm bảo kiểm tra giá trị của File
2, đây sẽ là một trong 3 giá trị
File
3 - Trình đọc đã được tạo, nhưng chưa có phương thức readAs nào được gọi. [TRỐNG RỖNG]File
4 - Một trong các phương thức readAs đã được gọi. Thao tác đọc đang diễn ra và chưa có lỗi nào xảy ra. [ĐANG TẢI]File
5 - Hoạt động đã kết thúc. Điều này có thể có nghĩa là một trong ba điều. ________ đã được đọc thành công, đã xảy ra lỗi đọc hoặcFile
8 đã được gọi và thao tác đã bị hủy. [XONG]
Thuộc tính files
9 sẽ chỉ được điền trong trường hợp thao tác đọc thành công. Trong tất cả các trường hợp khác, nó sẽ là File
9
Điều tương tự cũng áp dụng cho File
3 nên được truy cập bên trong trình xử lý sự kiện lỗi
Các loại sự kiện FileReader
Chúng ta đã khám phá hai loại sự kiện đọc phổ biến nhất, giờ hãy nhanh chóng tìm hiểu phần còn lại. FileReader có sáu loại sự kiện
name
1 - được kích hoạt khi hoàn tất thành công thao tác đọcname
2 - được kích hoạt khi thao tác đọc gặp lỗiname
3 - được kích hoạt định kỳ trong khiFile
hoặcfiles
3 đang được đọc và chứa thông tin về tiến trình của hoạt động. Có thể được sử dụng để triển khai các thanh tảiname
6 - được kích hoạt khi thao tác đọc bị hủy, tôi. e. khiFile
8 được gọiname
8 - được kích hoạt khi thao tác đọc bắt đầuname
9 - được kích hoạt khi thao tác đọc kết thúc, bất kể thao tác đó thành công hay thất bại
Bạn có thể nhận thấy rằng các sự kiện FileReader hoạt động tương tự như các sự kiện DOM thông thường. Tôi thấy rằng suy nghĩ về chúng như vậy sẽ giúp hiểu bản chất phi tuyến tính, không đồng bộ của chúng dễ dàng hơn rất nhiều
💡 Chú thích bên lề. Giống như với các sự kiện DOM, có thể đăng ký trình xử lý sự kiện bằng cách sử dụng size
0 hoặc bằng cách gán hàm gọi lại cho thuộc tính "oneeventname" của trình đọc
Bãi. chữ[]
Cũng cần lưu ý rằng để đọc các tệp văn bản, tồn tại một phương pháp mới hơn và đơn giản hơn. size
1. Hãy nhớ rằng File
chỉ là một files
3 với một số chức năng bổ sung, vì vậy nó kế thừa tất cả các phương thức của Blob, bao gồm cả phương thức này. Điều này có nghĩa là bạn có thể sử dụng phương pháp này trên cả Blobs và Files
Nó không trông đẹp hơn sao? . API này khá mới và hỗ trợ trình duyệt vẫn còn khá kém
Làm việc với hình ảnh
Bây giờ chúng ta đã biết cách đọc tệp văn bản, hãy chuyển sang phần thú vị hơn. hình ảnh. Để minh họa chủ đề này, chúng ta sẽ xây dựng một bản xem trước đơn giản của hình ảnh đã chọn
Loại tập tin
Trước tiên, hãy đảm bảo rằng tệp đã chọn thực sự là một hình ảnh. Chúng ta có thể làm điều đó với sự trợ giúp của thuộc tính size
4
Thuộc tính size
4, cho phép bạn chỉ định loại tệp nào người dùng sẽ được phép chọn. Nó sử dụng một danh sách xác định loại tệp duy nhất được phân tách bằng dấu phẩy. Mỗi công cụ xác định loại có thể ở một trong các định dạng sau
- Phần mở rộng tên tệp không phân biệt chữ hoa chữ thường, bắt đầu bằng dấu chấm [“. "] nhân vật. Ví dụ. ________ 56, ________ 57, ________ 58, ________ 59
- Một loại MIME, ví dụ. ________ 60, ________ 61, ________ 62, ________ 63
type
4 có nghĩa là "bất kỳ tệp hình ảnh nào"type
5 có nghĩa là "bất kỳ tệp âm thanh nào"type
6 có nghĩa là "bất kỳ tệp video nào"
Bạn có thể trộn và kết hợp những thứ này để phù hợp với trường hợp sử dụng cụ thể của mình
Xác thực HTML không hoàn hảo mặc dù. Ví dụ: trên Windows, nó sẽ chỉ ẩn các tệp không phù hợp với tiêu chí của bạn, nhưng bạn vẫn có thể chọn “Tất cả tệp [*. *]” hoặc sử dụng tính năng kéo và thả để chọn bất kỳ tệp nào bạn muốn. Tất cả điều này có nghĩa là bạn cũng nên kiểm tra loại tệp bên trong mã javascript của mình
Hoặc bạn có thể thiết lập các luồng xử lý riêng cho các loại tệp khác nhau
Thật không may, type
7 và type
8 không hoạt động trong các trình duyệt cũ hơn như Internet Explorer, vì vậy nếu bạn cần hỗ trợ chúng, bạn có thể muốn xem xét một số giải pháp thay thế hoặc polyfill
Ngoài ra, hãy nhớ rằng “bất kỳ tệp hình ảnh nào” sẽ khớp [trong số những tệp khác]
- hình ảnh có hỗ trợ trình duyệt kém hoàn hảo, như
type
9 - hình ảnh có độ trong suốt, như
lastModified
0 - hình ảnh hoạt hình, như của
lastModified
1
Vì vậy, hãy đảm bảo rằng bạn hỗ trợ tất cả các chức năng này hoặc chỉ xác định rõ ràng những loại bạn dự định hỗ trợ
URL dữ liệu & URL đối tượng
Để hiển thị một hình ảnh đã chọn, chúng tôi sẽ cần một HTML img và một URL cho thuộc tính lastModified
2. Có hai cách khác nhau để thể hiện tệp hình ảnh dưới dạng URL. một dataURL và objectURL. Có một số khác biệt quan trọng giữa hai loại này, vì vậy hãy nhanh chóng lướt qua chúng
URL dữ liệu
Đó là kết quả của lastModified
3. Đó là một chuỗi chứa loại tệp và dữ liệu nhị phân thực tế của tệp, được mã hóa bằng base64
Định dạng của nó có thể thay đổi một chút tùy thuộc vào loại dữ liệu mà nó đại diện, nhưng đối với hầu hết các tệp, nó trông như thế này. lastModified
4, trong đó lastModified
5 là loại MIME và lastModified
6 là tệp được mã hóa base64
Bởi vì nó thực sự chứa dữ liệu của tệp nên nó có thể được sử dụng ở bất cứ đâu sau khi được tạo mà không cần tệp gốc. Tuyệt đấy
URL đối tượng
Còn được gọi là URL blob. Đó là kết quả của lastModified
7. Nó là một API mới hơn, nhưng vẫn được hỗ trợ khá tốt. Tuy nhiên, nó sẽ không hoạt động trong IE phiên bản 9 trở xuống
Nó nhanh hơn và ngắn gọn hơn lastModified
8 nhưng nó đi kèm với những vấn đề đau đầu và hạn chế của riêng nó. Ngược lại với dataURL, nó không chứa bất kỳ tệp dữ liệu nào. Nó chỉ là một tham chiếu đến một tập tin. Một điểm khác biệt quan trọng nữa là lastModified
7 đồng bộ
ObjectURL phải được thu hồi khi không còn cần thiết. Trình duyệt sẽ tự động thực hiện khi tài liệu được tải xuống, tuy nhiên để đạt hiệu suất tối ưu và sử dụng bộ nhớ, bạn không nên dựa vào hành vi đó, đặc biệt là trong các ứng dụng lớn có nhiều URL đối tượng. Thay vào đó, bạn nên gọi rõ ràng Date
0 khi url không còn cần thiết, ví dụ như trong trình xử lý sự kiện Date
1, chúng ta sẽ thảo luận sau
💡 Chú thích bên lề. để lấy dữ liệu tệp được mã hóa base64 từ một dataURL, chỉ cần trích xuất một phần của chuỗi sau dấu phẩy, như thế này. Date
2
Hiển thị hình ảnh đã chọn
Hầu hết các URL đối tượng và URL dữ liệu có thể được sử dụng thay thế cho nhau, nhưng chúng đều có điểm mạnh và điểm yếu riêng. Điều này có nghĩa là bạn có thể nên tìm hiểu cả hai và chọn cái nào sẽ sử dụng trong từng trường hợp cụ thể. Hãy xem xét các ví dụ về cả hai, để hiểu rõ hơn về cách thức hoạt động của từng loại
Sử dụng FileReader & dataURL
- Chúng tôi đăng ký một trình lắng nghe sự kiện thay đổi trên đầu vào tệp
- Bên trong cuộc gọi lại
files
7, chúng tôi lấy tệp đã chọn và tạo một phiên bản củalastModified
8 - Chúng tôi đăng ký một trình lắng nghe sự kiện tải trên đầu đọc
- Bên trong cuộc gọi lại
Date
5, chúng tôi tạo một phần tử hình ảnh mới, - Sau đó, chúng tôi lấy dataURL từ
files
9 [hãy nhớ rằng,Date
7 trỏ đếnDate
8] và gán nó cho thuộc tínhlastModified
2 giống như trong HTML - Sau khi thuộc tính src được đặt, chúng tôi sẽ nối toàn bộ phần tử
File
0 vào DOM với tư cách là phần tử con của previewContainer của chúng tôi. [Thực ra chúng ta có thể vừa tạo thẻFile
0 trong HTML và cập nhật thuộc tính src trong javascript, nhưng làm theo cách này thực sự chuẩn bị cho chúng ta làm việc với nhiều hình ảnh cùng một lúc và thao tác với hình ảnh trong mộtFile
2] - Khi mọi thứ đã được thiết lập, chúng tôi bắt đầu thao tác đọc bằng cách sử dụng
File
3, thao tác này sẽ kích hoạt trình ngheDate
5 của chúng tôi khi đọc xong tệp
Sử dụng objectURL
- Chúng tôi đăng ký một trình lắng nghe sự kiện thay đổi trên đầu vào tệp
- Bên trong cuộc gọi lại
files
7, chúng tôi lấy tệp đã chọn và tạo một phần tử hình ảnh mới - Chúng tôi đăng ký một trình xử lý sự kiện tải trên hình ảnh
- Bên trong cuộc gọi lại
Date
5,Date
0 sẽ thu hồi objectURL sau khi hình ảnh được tải đầy đủ và url không còn cần thiết nữa. Bước này không cần thiết, nhưng rất khuyến khích. Hãy nhớ rằng nếu sau này bạn cần url đó ở một nơi khác, thì bạn chưa nên thu hồi nó - Khi hình ảnh được tải đầy đủ, chúng tôi sẽ không cần objectURL nữa. Vì vậy, bên trong cuộc gọi lại
Date
5, chúng tôi thu hồi url đó. Để làm điều đó, chúng tôi chuyển nó làm đối số choDate
0. Chúng ta có thể lấy url trực tiếp từ thuộc tính src của hình ảnh - Chúng tôi tạo objectURL, bằng cách chuyển tệp đã chọn làm đối số cho
lastModified
7 và gán nó cho thuộc tínhlastModified
2 - Sau khi thuộc tính src được đặt, chúng tôi sẽ nối toàn bộ phần tử
File
0 vào DOM với tư cách là phần tử con của previewContainer của chúng tôi
💡 Chú thích bên lề. Ở những nơi khác, bạn có thể thấy các hình ảnh được tạo bằng cách sử dụng hàm tạo Hình ảnh i. e. files
03. Hầu hết thời gian nó tương đương với files
04 và tôi chưa bao giờ gặp vấn đề gì với cả hai. Tuy nhiên, có thể có một số trường hợp cạnh [được mô tả trong chuỗi StackOverflow này], điều này dường như làm cho trường hợp sau trở thành một tùy chọn đáng tin cậy hơn
FileList
Trước khi chúng tôi chuyển sang đọc nhiều tệp, hãy làm rõ một số thứ. Thuộc tính files
không thực sự là một files
06, mặc dù nó trông giống như một 😮. Đó là một kiểu dữ liệu đặc biệt của files
07. Điều này có nghĩa là nó không có quyền truy cập vào các phương thức mảng thông thường [như files
08, files
09, files
10], do đó, để lặp lại danh sách, bạn sẽ phải sáng tạo. Tôi sẽ chỉ cho bạn một vài cách khác nhau để làm điều này, nhưng nếu bạn muốn biết thêm, hãy xem chủ đề StackOverflow này
Bạn cũng có thể nhận thấy rằng mặc dù chúng tôi chỉ làm việc với một tệp duy nhất [cho đến bây giờ], chúng tôi luôn phải viết files
11. Đó là bởi vì bất kể thuộc tính files
12 có được thiết lập hay không, thì files
13 luôn là một files
07. Điều này có nghĩa là ngay cả khi đầu vào chỉ chấp nhận một tệp, bạn vẫn phải cung cấp chỉ mục, trong trường hợp chỉ có một mục là 0
💡 Chú thích bên lề. Theo dự thảo làm việc của w3c, files
07 có thể được thay thế bằng một files
06 thông thường trong tương lai gần. Bắt chéo ngón tay 🤞
Giao diện FileList nên được coi là "có nguy cơ" vì xu hướng chung trên Nền tảng web là thay thế các giao diện đó bằng đối tượng nền tảng Array trong ECMAScript [ECMA-262]. Đặc biệt, điều này có nghĩa là cú pháp sắp xếp filelist. mục [0] có nguy cơ;
Đọc nhiều tệp
Mặc định file input chỉ cho phép ta chọn 1 file duy nhất. Để cho phép chọn nhiều tệp cùng lúc, hãy thêm thuộc tính files
12 vào phần tử html
Trong ví dụ này, tôi sẽ sử dụng lastModified
8 vì nó không đồng bộ và sẽ không chặn giao diện người dùng khi xử lý nhiều tệp. Nhưng nếu bạn muốn, bạn có thể sử dụng objectURL để thay thế và trong hầu hết các trường hợp, bạn sẽ ổn thôi
Bởi vì chúng ta đã làm hầu hết điều này trước đây, nên tôi sẽ chỉ sử dụng nhận xét để gọi ra các phần quan trọng của mã. Nếu bạn đã bỏ qua các phần trước, tôi khuyên bạn nên quay lại và bắt kịp, tôi sẽ đợi 😉⏳
Như bạn có thể thấy, chúng tôi tạo một phiên bản lastModified
8 riêng biệt cho mọi tệp. Điều tương tự có thể đạt được bằng cách gọi files
20 bên trong trình xử lý sự kiện name
9, nhưng cách này thực hiện công việc và dù sao cũng có thể nhanh hơn
Đây là một bản tóm tắt về toàn bộ quy trình xử lý tệp, bao gồm tất cả các lớp và phương thức liên quan
Cảm ơn vì đã đọc
Nếu có điều gì đó không rõ ràng hoặc bạn muốn tôi mở rộng về chủ đề nào đó, hãy cho tôi biết trong phần nhận xét
Các bài viết thú vị khác
Tìm hiểu tất cả 8 thuộc tính CSS nền trong 5 phút
Giới thiệu nhanh nhưng đầy đủ về thuộc tính nền CSS
hadrysmateusz. Trung bình. com
Hướng dẫn đầy đủ về CSS Gradients
Chuyển màu đang quay trở lại, hãy đảm bảo bạn biết cách sử dụng chúng
hadrysmateusz. Trung bình. com
20 bộ chọn CSS bạn cần biết
Đảm bảo bạn biết các Bộ chọn CSS quan trọng này
Trung bình. com
Ngoài ra, nếu bạn là một người hâm mộ Vivaldi như tôi, hãy xem Trình tạo hình thu nhỏ Vivaldi của tôi, đó là một công cụ miễn phí do tôi tạo ra vì tôi đã quá mệt mỏi với việc tạo hình thu nhỏ theo cách thủ công. Nó sử dụng rất nhiều khái niệm từ bài đăng này và bạn có thể xem toàn bộ mã nguồn trên GitHub