Bước 5: Thêm hình ảnh từ web

Trong bước này, bạn sẽ tìm hiểu:

  • Cách tải tài nguyên từ bên ngoài ứng dụng của bạn và thêm chúng vào DOM thông qua XHR và ObjectURLs.

Thời gian ước tính để hoàn tất bước này: 20 phút.
Để xem trước những nội dung bạn sẽ hoàn tất ở bước này, hãy chuyển xuống cuối trang này ↓.

Cách CSP ảnh hưởng đến việc sử dụng tài nguyên bên ngoài

Nền tảng Ứng dụng Chrome buộc ứng dụng của bạn phải hoàn toàn tuân thủ Chính sách bảo mật nội dung (CSP). Bạn không thể tải trực tiếp các tài nguyên DOM như hình ảnh, phông chữ và CSS từ bên ngoài Gói ứng dụng Chrome.

Nếu muốn hiển thị hình ảnh bên ngoài trong ứng dụng, bạn cần yêu cầu hình ảnh đó qua XMLHttpRequest, chuyển đổi hình ảnh đó thành Blob rồi tạo ObjectURL. Bạn có thể thêm ObjectURL này vào DOM vì nó tham chiếu đến một mục trong bộ nhớ theo bối cảnh của ứng dụng.

Hiển thị hình ảnh thu nhỏ cho các mục việc cần làm

Hãy thay đổi ứng dụng để tìm URL hình ảnh trong một mục việc cần làm. Nếu URL trông giống một hình ảnh (ví dụ: kết thúc bằng .png, .jpg, .svg hoặc .gif), hãy áp dụng quy trình nêu trên để hiển thị hình thu nhỏ của hình ảnh bên cạnh URL.

Cập nhật quyền

Trong ứng dụng Chrome, bạn có thể thực hiện lệnh gọi XMLHttpRequest tới bất kỳ URL nào, miễn là bạn đã chỉ định miền của URL đó trong tệp kê khai. Vì bạn không biết trước người dùng sẽ nhập URL hình ảnh nào, nên hãy xin phép để gửi yêu cầu đến "<all_urls>".

Trong tệp manifest.json, hãy yêu cầu cấp quyền "":

"permissions": ["storage", "alarms", "notifications",
                "webview", "<all_urls>"],

Tạo và xoá ObjectURL

Trong controller.js, hãy thêm phương thức _createObjectURL() để tạo ObjectURLs từ Blob:

Controller.prototype._createObjectURL = function(blob) {
  var objURL = URL.createObjectURL(blob);
  this.objectURLs = this.objectURLs || [];
  this.objectURLs.push(objURL);
  return objURL;
};

ObjectURL giữ lại bộ nhớ, vì vậy khi không cần ObjectURL nữa, bạn nên thu hồi ObjectURL. Thêm phương thức _clearObjectURL() này vào controller.js để xử lý điều đó:

Controller.prototype._clearObjectURL = function() {
  if (this.objectURLs) {
    this.objectURLs.forEach(function(objURL) {
      URL.revokeObjectURL(objURL);
    });
    this.objectURLs = null;
  }
};

Tạo yêu cầu XHR

Thêm phương thức _requestRemoteImageAndAppend() để thực thi XMLHttpRequest trên một URL hình ảnh nhất định:

Controller.prototype._requestRemoteImageAndAppend = function(imageUrl, element) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', imageUrl);
  xhr.responseType = 'blob';
  xhr.onload = function() {
    var img = document.createElement('img');
    img.setAttribute('data-src', imageUrl);
    img.className = 'icon';
    var objURL = this._createObjectURL(xhr.response);
    img.setAttribute('src', objURL);
    element.appendChild(img);
  }.bind(this);
  xhr.send();
};

Khi tải XHR, phương thức này tạo một ObjectURL từ phản hồi của XHR và thêm một phần tử <img>ObjectURL này vào DOM.

Phân tích cú pháp URL hình ảnh trong các mục việc cần làm

Bây giờ, hãy thêm phương thức _parseForImageURLs() để tìm mọi đường liên kết chưa được xử lý và kiểm tra hình ảnh. Đối với mỗi URL trông giống như một hình ảnh, hãy thực thi _requestRemoteImageAndAppend():

Controller.prototype._parseForImageURLs = function () {
  // remove old blobs to avoid memory leak:
  this._clearObjectURL();
  var links = this.$todoList.querySelectorAll('a[data-src]:not(.thumbnail)');
  var re = /\.(png|jpg|jpeg|svg|gif)$/;
  for (var i = 0; i<links.length; i++) {
    var url = links[i].getAttribute('data-src');
    if (re.test(url)) {
      links[i].classList.add('thumbnail');
      this._requestRemoteImageAndAppend(url, links[i]);
    }
  }
};

Hiển thị hình thu nhỏ trong danh sách việc cần làm

Bây giờ, hãy gọi _parseForImageURLs() từ showAll(), showActive()showCompleted():

/**
 * An event to fire on load. Will get all items and display them in the
 * todo-list
 */
Controller.prototype.showAll = function () {
  this.model.read(function (data) {
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
    this._parseForImageURLs();
  }.bind(this));
};

/**
 * Renders all active tasks
 */
Controller.prototype.showActive = function () {
  this.model.read({ completed: 0 }, function (data) {
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
    this._parseForImageURLs();
  }.bind(this));
};

/**
 * Renders all completed tasks
 */
Controller.prototype.showCompleted = function () {
  this.model.read({ completed: 1 }, function (data) {
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
    this._parseForImageURLs();
  }.bind(this));
};

Làm tương tự đối với editItem():

Controller.prototype.editItem = function (id, label) {
  ...
  var onSaveHandler = function () {
    ...
    if (value.length && !discarding) {
      ...
      label.innerHTML = this._parseForURLs(value);
      this._parseForImageURLs();
    } else if (value.length === 0) {
  ...
}

Giới hạn kích thước hình ảnh hiển thị

Cuối cùng, trong _bowercomponents/todomvc-common/base.css, hãy thêm quy tắc CSS để giới hạn kích thước của hình ảnh:

.thumbnail img[data-src] {
  max-width: 100px;
  max-height: 28px;
}

Chạy ứng dụng Todo đã hoàn thiện

Bạn đã hoàn tất Bước 5! Tải lại ứng dụng và thêm mục việc cần làm có URL đến hình ảnh được lưu trữ trực tuyến. Một số URL bạn có thể sử dụng: http://goo.gl/nqHMF#.jpg hoặc http://goo.gl/HPBGR#.png.

Thông tin khác

Để biết thêm thông tin chi tiết về một số API được giới thiệu trong bước này, hãy tham khảo:

Bạn đã sẵn sàng để tiếp tục bước tiếp theo? Chuyển đến Bước 6 – Xuất việc cần làm sang hệ thống tệp »