步驟 5:從網路新增圖片

在這個步驟中,您將瞭解:

  • 如何從應用程式外部載入資源,並透過 XHR 和 ObjectURL 將資源新增至 DOM。

預計完成這個步驟的時間:20 分鐘。
如要預覽這個步驟中要完成的內容,請向下跳到本頁底部 ↓

CSP 對外部資源使用的影響

Chrome 應用程式平台會強制您的應用程式完全符合內容安全政策 (CSP)。您無法直接從 Chrome 應用程式套件外部載入圖片、字型和 CSS 等 DOM 資源。

如要在應用程式中顯示外部圖片,您必須透過 XMLHttpRequest 要求圖片,然後將其轉換為 Blob,並建立 ObjectURL。這個 ObjectURL 可在應用程式環境中參照記憶體內項目,因此可以新增至 DOM。

顯示待辦事項縮圖

讓我們變更應用程式,尋找待辦事項中的圖片網址。如果網址的格式是圖片 (例如結尾為 .png、.jpg、.svg 或 .gif),請套用上述程序,在網址旁邊顯示圖片縮圖。

更新權限

在 Chrome 應用程式中,只要您在資訊清單中指定網域,就可以對任何網址進行 XMLHttpRequest 呼叫。由於您不會事先得知使用者會輸入的圖片網址,因此請向 "<all_urls>" 要求權限。

manifest.json 中取得「」權限

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

建立及清除 ObjectURL

controller.js 中,新增 _createObjectURL() 方法以從 Blob 建立 ObjectURL:

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

ObjectURL 會保留記憶體,因此當您不再需要 ObjectURL 時,請予以撤銷。將此 _clearObjectURL() 方法新增至 controller.js 即可:

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

提出 XHR 要求

新增 _requestRemoteImageAndAppend() 方法,在指定圖片網址上執行 XMLHttpRequest:

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();
};

在 XHR 載入時,這個方法會從 XHR 的回應建立 ObjectURL,並將具有此 ObjectURL<img> 元素新增至 DOM。

剖析待辦事項中的圖片網址

現在請新增 _parseForImageURLs() 方法,以找出所有尚未處理的連結,並檢查是否有圖片。對每個類似圖片的網址執行 _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]);
    }
  }
};

在待辦事項清單中顯示縮圖

現在從 showAll()showActive()showCompleted() 呼叫 _parseForImageURLs()

/**
 * 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));
};

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) {
  ...
}

限制顯示圖片的尺寸

最後,在 _bowercomponents/todomvc-common/base.css 中新增 CSS 規則來限制圖片尺寸:

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

啟動已完成的待辦事項應用程式

您已完成步驟 5!重新載入應用程式,然後新增待辦事項項目,並附上線上代管圖片的網址。你可以使用下列網址:http://goo.gl/nqHMF#.jpghttp://goo.gl/HPBGR#.png

瞭解詳情

如要進一步瞭解這個步驟介紹的某些 API,請參閱:

準備好繼續進行下一步了嗎?請參閱步驟 6 - 將待辦事項匯出至檔案系統 »