第 5 步:从网络添加图片

在此步骤中,您将学习以下内容:

  • 如何通过 XHR 和 Object网址s 从应用外部加载资源,并将资源添加到 DOM 中。

完成此步骤的预计用时:20 分钟。
如需预览您将在此步骤中完成的内容,请跳至本页面底部 ↓

CSP 对外部资源的使用有何影响

Chrome 应用平台会强制您的应用完全遵守内容安全政策 (CSP)。 您无法从 Chrome 应用软件包外部直接加载 DOM 资源(例如图片、字体和 CSS)。

如果您要在应用中显示外来图片,则需要通过 XMLHttpRequest 请求该图片,将其转换为 Blob,然后创建一个 ObjectURL。此 ObjectURL 可以添加到 DOM 中,因为它在应用的上下文中引用了内存中的项。

显示待办事项缩略图

让我们更改应用,以在待办事项中查找图片网址。如果网址看起来像图片(例如,以 .png、.jpg、.svg 或 .gif 结尾),请应用上述流程,以便在网址旁边显示图片缩略图。

更新权限

在 Chrome 应用中,只要您在清单中指定网址的网域,就可以对任何网址进行 XMLHttpRequest 调用。由于您事先不知道用户将输入什么图片网址,因此请请求相应权限以向 "<all_urls>" 发出请求。

manifest.json 中,请求“”权限

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

创建并清除 Object网址s

controller.js 中,添加 _createObjectURL() 方法以从 Blob 创建 Object网址:

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

Object网址 占用内存,因此当您不再需要 Object网址 时,应将其撤消。将此 _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 步 - 将待办事项导出到文件系统 »