Browser: Firefox, IE
Play here
Nếu một trang web có nhiều hình ảnh, chúng sẽ được trình duyệt tải về từ từ, tải được đến đâu hiển thị đến đó. Ok, nhưng nếu chúng ta ko muốn người dùng tương tác với hình ảnh trước khi chúng được tải về đầy đủ thì sao? Cách giải quyết là đầu tiên chỉ hiện lên màn hình "Loading…", đồng thời tiến hành tải ảnh vào bộ đệm của trình duyệt, sau khi tải xong thì mới cho hiện lên trang web đầy đủ.
Và chúng ta phải dùng JavaScript (xin đừng nhầm với Java, chúng hoàn toàn khác nhau). Một trong những thế mạnh to bự của JavaScript là nó có thể chọc ngoáy vào mã HTML vốn là tĩnh. Trang web ban đầu chỉ là mã HTML tĩnh để hiện "Loading…", khi tải xong, dùng Node.removeChild() để xóa chữ "Loading…", kế tiếp dùng Node.appendChild() để đưa vào nội dung chính.
Một sai lầm phổ biến tôi thường thấy là code đơn giản như sau:
var oImg = new Image;
oImg.src = "abc.jpg";
Câu lệnh thứ 2 sẽ mở ra một Thread mới, Thread này âm thầm tải ảnh "abc.jpg" vào bộ đệm, đồng thời, ko cần biết đã tải xong hay chưa, ngay tắp lự chạy dòng lệnh tiếp theo. Thế là hỏng việc!
Vậy thì vấn đề là ta phải túm được thời điểm tất cả các ảnh đã tải xong hết!
Bây giờ ta sẽ tạo 1 lớp tên là ImagePreloader, trong contructor của lớp này nhận vào 2 tham số là mảng URL của các tấm hình và tên gọi của hàm sẽ được thực thi sau khi tải xong hết các tấm hình ấy:
function ImagePreloader(images, call-back) {
// store the call-back
this.call-back = call-back;
// initialize internal state
this.nLoaded = 0;
this.nProcessed = 0;
this.aImages = new Array;
// record the number of images
this.nImages = images.length;
// for each image, call preload()
for (var i = 0; i < images.length; i++)
this.preload(images[i]);
}
Hàm call-back được lưu lại để sử dụng sau này, các URL được truyền vào hàm preload:
ImagePreloader.prototype.preload = function(image) {
// create new Image object and add to array
var oImage = new Image;
this.aImages.push(oImage);
// set up event handlers for the Image object
oImage.onload = ImagePreloader.prototype.onload;
oImage.onerror = ImagePreloader.prototype.onerror;
oImage.onabort = ImagePreloader.prototype.onabort;
// assign pointer back to this
oImage.oImagePreloader = this;
oImage.bLoaded = false;
// assign the .src property of the Image object
oImage.src = image;
}
Hàm preload tạo ra 1 đối tượng Image mới, cho nó đăng kí 3 sự kiện: onload, onerror, onabort. onload được gọi khi tải thành công, onerror khi có lỗi và onabort khi user ngưng tải bằng cách nhấn nút Stop trên Toolbar của trình duyệt. Các câu lệnh tiếp theo đều dễ hiểu.
Cuối cùng, ta cài đặt sự kiện:
ImagePreloader.prototype.onComplete = function() {
this.nProcessed++;
if ( this.nProcessed == this.nImages ) {
this.call-back(this.aImages, this.nLoaded);
}
}
ImagePreloader.prototype.onload = function() {
this.bLoaded = true;
this.oImagePreloader.nLoaded++;
this.oImagePreloader.onComplete();
}
ImagePreloader.prototype.onerror = function() {
this.bError = true;
this.oImagePreloader.onComplete();
}
ImagePreloader.prototype.onabort = function() {
this.bAbort = true;
this.oImagePreloader.onComplete();
}
Chú ý từ khóa this, theo lẽ thường, this sẽ trỏ vào lớp ImagePreloader, tuy nhiên ở trong ngữ cảnh này, this lại trỏ vào đối tượng Image xin đăng kí sự kiện.

Recent Comments