ขั้นตอนที่ 5: เพิ่มรูปภาพจากเว็บ

ในขั้นตอนนี้ คุณจะได้เรียนรู้เกี่ยวกับสิ่งต่อไปนี้

  • วิธีโหลดทรัพยากรจากภายนอกแอปและเพิ่มลงใน DOM ผ่าน XHR และ ObjectURL

เวลาโดยประมาณในการทำขั้นตอนนี้ให้เสร็จสิ้นคือ 20 นาที
หากต้องการดูตัวอย่างขั้นตอนที่ต้องทำในขั้นตอนนี้ ให้เลื่อนลงไปที่ด้านล่างของหน้านี้ ↓

CSP ส่งผลต่อการใช้ทรัพยากรภายนอกอย่างไร

แพลตฟอร์มแอป Chrome จะบังคับให้แอปของคุณปฏิบัติตามนโยบายรักษาความปลอดภัยเนื้อหา (CSP) โดยสมบูรณ์ คุณจะโหลดทรัพยากร DOM เช่น รูปภาพ แบบอักษร และ CSS จากภายนอกแพ็กเกจแอป Chrome โดยตรงไม่ได้

หากต้องการแสดงภาพภายนอกในแอป คุณจะต้องขอผ่าน XMLHttpRequest เปลี่ยนรูปแบบเป็น Blob และสร้าง ObjectURL ObjectURL นี้สามารถเพิ่มลงใน DOM ได้เพราะหมายถึงรายการในหน่วยความจำในบริบทของแอป

แสดงภาพขนาดย่อของรายการสิ่งที่ต้องทำ

มาเปลี่ยนแอปเพื่อหา URL ของรูปภาพในรายการสิ่งที่ต้องทำกัน หาก URL ดูเหมือนรูปภาพ (เช่น ลงท้ายด้วย .png, .jpg, .svg หรือ .gif) ให้ใช้ขั้นตอนที่กล่าวข้างต้นเพื่อแสดงภาพขนาดย่อของรูปภาพข้าง URL

อัปเดตสิทธิ์

ในแอป Chrome คุณสามารถเรียก XMLHttpRequest ไปยัง URL ใดก็ได้ตราบใดที่คุณระบุโดเมนของ URL นั้นในไฟล์ Manifest เนื่องจากคุณจะไม่ทราบล่วงหน้าว่าผู้ใช้จะพิมพ์ URL รูปภาพใด ให้ขออนุญาตเพื่อส่งคำขอไปยัง "<all_urls>"

ใน manifest.json ให้ขอสิทธิ์ "":

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

สร้างและล้าง ObjectURL

ใน controller.js ให้เพิ่มเมธอด _createObjectURL() เพื่อสร้าง ObjectURL จาก Blob

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

ObjectURL จะมีหน่วยความจำเหลืออยู่ ดังนั้นเมื่อคุณไม่จำเป็นต้องใช้ ObjectURL แล้ว คุณควรเพิกถอน URL เหล่านั้น เพิ่มเมธอด _clearObjectURL() นี้ลงใน controller.js เพื่อจัดการ

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

ส่งคำขอ XHR

เพิ่มเมธอด _requestRemoteImageAndAppend() เพื่อเรียกใช้ XMLHttpRequest บน URL รูปภาพที่ระบุ

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 เมธอดนี้จะสร้าง ObjectURL จากการตอบสนองของ XHR และเพิ่มองค์ประกอบ <img> ที่มี ObjectURL นี้ลงใน DOM

แยกวิเคราะห์ URL ของรูปภาพในรายการสิ่งที่ต้องทำ

ตอนนี้ให้เพิ่มเมธอด _parseForImageURLs() ที่จะค้นหาลิงก์ทั้งหมดที่ยังไม่ได้ประมวลผล แล้วตรวจหารูปภาพ สำหรับ URL แต่ละรายการที่มีลักษณะเหมือนรูปภาพ ให้ดำเนินการ _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]);
    }
  }
};

แสดงภาพขนาดย่อในรายการสิ่งที่ต้องทำ

ขณะนี้โทรหา _parseForImageURLs() จาก 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));
};

ให้ทำแบบเดียวกันนี้สำหรับ 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;
}

เปิดแอป Todo ที่เสร็จแล้ว

คุณทำขั้นตอนที่ 5 เสร็จแล้ว โหลดแอปซ้ำและเพิ่มรายการสิ่งที่ต้องทำที่มี URL ไปยังรูปภาพที่โฮสต์ออนไลน์ คุณสามารถใช้ URL บางรายการ เช่น http://goo.gl/nqHMF#.jpg หรือ http://goo.gl/HPBGR#.png

สำหรับข้อมูลเพิ่มเติม

สำหรับข้อมูลโดยละเอียดเพิ่มเติมเกี่ยวกับ API บางส่วนที่นำมาใช้ในขั้นตอนนี้ โปรดดูที่:

หากพร้อมที่จะไปยังขั้นตอนถัดไปแล้ว ไปที่ขั้นตอนที่ 6 - ส่งออกสิ่งที่ต้องทำไปยังระบบไฟล์ »