การนำทางการ์ด

ส่วนเสริมแบบการ์ดส่วนใหญ่สร้างขึ้นโดยใช้การ์ดหลายใบที่แสดง "หน้า" ต่างๆ ของอินเทอร์เฟซส่วนเสริม คุณควรใช้การไปยังส่วนต่างๆ ระหว่างการ์ดในส่วนเสริมอย่างง่ายดายและเป็นธรรมชาติเพื่อให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่มีประสิทธิภาพ

ในเดิมในส่วนเสริมของ Gmail การเปลี่ยนระหว่างการ์ดต่างๆ ของ UI จะจัดการโดยการผลักและแสดงการ์ดเข้าและออกจากกองการ์ดเดียว โดย Gmail จะแสดงการ์ดบนสุดของกอง

การนำทางการ์ดในหน้าแรก

ส่วนเสริมของ Google Workspace เปิดตัวหน้าแรกและการ์ดที่ไม่อิงตามบริบท ส่วนเสริมของ Google Workspace มีกองการ์ดภายในสำหรับแต่ละรายการเพื่อรองรับการ์ดตามบริบทและไม่ตามบริบท เมื่อเปิดส่วนเสริมในโฮสต์ homepageTrigger ที่เกี่ยวข้องจะทํางานเพื่อสร้างการ์ดหน้าแรกแรกในกอง (การ์ด "หน้าแรก" สีน้ําเงินเข้มในแผนภาพด้านล่าง) หากไม่ได้กำหนด homepageTrigger ระบบจะสร้างการ์ดเริ่มต้น แสดง และส่งไปยังกองที่ไม่อิงตามบริบท การ์ดแรกนี้เป็นการ์ดรูท

ส่วนเสริมสามารถสร้างการ์ดที่ไม่อิงตามบริบทเพิ่มเติมและส่งไปยังกอง (การ์ด "ที่ส่ง" สีฟ้าในแผนภาพ) ขณะที่ผู้ใช้ไปยังส่วนต่างๆ ของส่วนเสริม UI ของส่วนเสริมจะแสดงการ์ดบนสุดในกอง ดังนั้นการกดการ์ดใหม่ลงในกองจะเปลี่ยนการแสดงผล และการดึงการ์ดออกจากกองจะเปลี่ยนการแสดงผลกลับเป็นการ์ดก่อนหน้า

หากส่วนเสริมมีทริกเกอร์ตามบริบทที่กําหนดไว้ ทริกเกอร์จะทํางานเมื่อผู้ใช้เข้าสู่บริบทนั้น ฟังก์ชันทริกเกอร์จะสร้างการ์ดตามบริบท แต่การแสดง UI จะอัปเดตตามDisplayStyleของการ์ดใหม่ ดังนี้

  • หาก DisplayStyle เป็น REPLACE (ค่าเริ่มต้น) การ์ดตามบริบท (การ์ด "ตามบริบท" สีส้มเข้มในแผนภาพ) จะแทนที่การ์ดที่แสดงอยู่ในปัจจุบัน ซึ่งจะเริ่มต้นกองการ์ดตามบริบทกองใหม่บนกองการ์ดที่ไม่ตามบริบทอย่างมีประสิทธิภาพ และการ์ดตามบริบทนี้เป็นการ์ดรูทของกองตามบริบท
  • หาก DisplayStyle เป็น PEEK แทน UI จะสร้างส่วนหัวที่แสดงข้อมูลโดยย่อซึ่งปรากฏที่ด้านล่างของแถบด้านข้างของส่วนเสริมแทน โดยจะวางซ้อนกับการ์ดปัจจุบัน ส่วนหัวของตัวอย่างจะแสดงชื่อของการ์ดใหม่และมีปุ่มควบคุมสำหรับผู้ใช้เพื่อให้ผู้ใช้ตัดสินใจว่าจะดูการ์ดใหม่หรือไม่ หากผู้ใช้คลิกปุ่มดู การ์ดนั้นจะแทนที่การ์ดปัจจุบัน (ตามที่อธิบายไว้ข้างต้นสำหรับREPLACE)

คุณสามารถสร้างการ์ดตามบริบทเพิ่มเติมและดันการ์ดเหล่านั้นลงในกองได้ ("การ์ดที่ดัน" สีเหลืองในแผนภาพ) การอัปเดตกองการ์ดจะเปลี่ยน UI ของส่วนเสริมให้แสดงการ์ดที่ด้านบนสุด หากผู้ใช้ออกจากบริบท ระบบจะนำการ์ดตามบริบทในกองออกและแสดงการ์ดหรือหน้าแรกที่ไม่ใช่ตามบริบทซึ่งอยู่ด้านบนสุด

หากผู้ใช้ป้อนบริบทที่ส่วนเสริมไม่ได้กำหนดทริกเกอร์ตามบริบทไว้ ระบบจะไม่สร้างการ์ดใหม่และการ์ดปัจจุบันจะยังคงแสดงอยู่

การดําเนินการ Navigation ที่อธิบายไว้ด้านล่างจะทํางานกับการ์ดจากบริบทเดียวกันเท่านั้น เช่น popToRoot() จากภายในการ์ดตามบริบทจะแสดงการ์ดตามบริบทอื่นๆ ทั้งหมดเท่านั้น และจะไม่ส่งผลต่อการ์ดในหน้าแรก

ในทางตรงกันข้าม ปุ่ม จะพร้อมให้ผู้ใช้ไปยังการ์ดที่ไม่ใช่ตามบริบทจากการ์ดตามบริบทเสมอ

คุณสร้างทรานซิชันระหว่างการ์ดได้โดยการเพิ่มหรือนำการ์ดออกจากกองการ์ด คลาส Navigation มีฟังก์ชันสำหรับส่งและแสดงไพ่จากกอง หากต้องการสร้างการนําทางการ์ดที่มีประสิทธิภาพ คุณต้องกําหนดค่าวิดเจ็ตให้ใช้การดําเนินการในการนําทาง คุณสามารถพุชหรือป๊อปการ์ดหลายใบพร้อมกันได้ แต่จะนําการ์ดหน้าแรกเริ่มต้นที่ระบบพุชลงในกองการ์ดเมื่อส่วนเสริมเริ่มทํางานออกไม่ได้

หากต้องการไปยังการ์ดใหม่เพื่อตอบสนองต่อการโต้ตอบของผู้ใช้กับวิดเจ็ต ให้ทําตามขั้นตอนต่อไปนี้

  1. สร้างออบเจ็กต์ Action และเชื่อมโยงกับฟังก์ชันการเรียกคืนที่คุณกำหนด
  2. เรียกฟังก์ชันตัวแฮนเดิลวิดเจ็ตที่เหมาะสมของวิดเจ็ตเพื่อตั้งค่า Action ในวิดเจ็ตนั้น
  3. ใช้ฟังก์ชัน Callback ที่ทําการนําทาง ฟังก์ชันนี้ได้รับออบเจ็กต์เหตุการณ์การดําเนินการเป็นอาร์กิวเมนต์ และต้องทําดังนี้
    1. สร้างออบเจ็กต์ Navigation เพื่อกำหนดการเปลี่ยนแปลงของการ์ด ออบเจ็กต์ Navigation รายการเดียวอาจมีขั้นตอนการนําทางหลายขั้นตอน ซึ่งจะดําเนินการตามลําดับที่เพิ่มลงในออบเจ็กต์
    2. สร้างออบเจ็กต์ ActionResponse โดยใช้คลาส ActionResponseBuilder และออบเจ็กต์ Navigation
    3. แสดงผลที่สร้างขึ้น ActionResponse

เมื่อสร้างตัวควบคุมการนําทาง คุณจะใช้ฟังก์ชันออบเจ็กต์ Navigation ต่อไปนี้

ฟังก์ชัน คำอธิบาย
Navigation.pushCard(Card) ดันการ์ดลงในกองปัจจุบัน ซึ่งจะต้องสร้างการ์ดให้เสร็จสมบูรณ์ก่อน
Navigation.popCard() นำไพ่ 1 ใบออกจากด้านบนของกอง เทียบเท่ากับการคลิกลูกศรกลับในแถวส่วนหัวของส่วนเสริม แต่จะไม่นำการ์ดรูทออก
Navigation.popToRoot() นำการ์ดทั้งหมดออกจากกองยกเว้นการ์ดรูท รีเซ็ตกองการ์ดนั้น
Navigation.popToNamedCard(String) แสดงการ์ดจากกองจนกว่าจะพบการ์ดที่มีชื่อที่ระบุหรือการ์ดรูทของกอง คุณกําหนดชื่อการ์ดได้โดยใช้ฟังก์ชัน CardBuilder.setName(String)
Navigation.updateCard(Card) แทนที่การ์ดปัจจุบันโดยที่ไม่ต้องย้ายข้อมูล โดยรีเฟรชการแสดงผลใน UI

หากการโต้ตอบหรือเหตุการณ์ของผู้ใช้ส่งผลให้มีการแสดงผลการ์ดอีกครั้งในบริบทเดียวกัน ให้ใช้เมธอด Navigation.pushCard(), Navigation.popCard() และ Navigation.updateCard() เพื่อแทนที่การ์ดที่มีอยู่ หากการโต้ตอบหรือเหตุการณ์ของผู้ใช้ส่งผลให้มีการแสดงผลการ์ดอีกครั้งในบริบทอื่น ให้ใช้ ActionResponseBuilder.setStateChanged() เพื่อบังคับให้เรียกใช้ส่วนเสริมอีกครั้งในบริบทเหล่านั้น

ตัวอย่างการนําทางมีดังนี้

  • หากการโต้ตอบหรือเหตุการณ์เปลี่ยนสถานะของการ์ดปัจจุบัน (เช่น การเพิ่มงานลงในรายการงาน) ให้ใช้ updateCard()
  • หากการโต้ตอบหรือเหตุการณ์ให้รายละเอียดเพิ่มเติมหรือแจ้งให้ผู้ใช้ดำเนินการเพิ่มเติม (เช่น การคลิกชื่อรายการเพื่อดูรายละเอียดเพิ่มเติม หรือการกดปุ่มเพื่อสร้างกิจกรรมใหม่ในปฏิทิน) ให้ใช้ pushCard() เพื่อแสดงหน้าใหม่ขณะที่อนุญาตให้ผู้ใช้ออกจากหน้าใหม่ได้โดยใช้ปุ่มย้อนกลับ
  • หากการโต้ตอบหรือเหตุการณ์อัปเดตสถานะในการ์ดก่อนหน้า (เช่น การอัปเดตชื่อของรายการจากมุมมองรายละเอียด) ให้ใช้เงื่อนไขอย่างเช่น popCard(), popCard(), pushCard(previous) และ pushCard(current) เพื่ออัปเดตการ์ดก่อนหน้าและการ์ดปัจจุบัน

การรีเฟรชการ์ด

ส่วนเสริม Google Workspace ช่วยให้ผู้ใช้รีเฟรชการ์ดได้โดยเรียกใช้ฟังก์ชันทริกเกอร์ Apps Script ที่ลงทะเบียนไว้ในไฟล์ Manifest อีกครั้ง ผู้ใช้เรียกให้รีเฟรชผ่านรายการเมนูของส่วนเสริม ดังนี้

แถบด้านข้างของส่วนเสริม Google Workspace

ระบบจะเพิ่มการดำเนินการนี้ลงในการ์ดที่สร้างขึ้นโดยฟังก์ชันทริกเกอร์ homepageTrigger หรือ contextualTrigger โดยอัตโนมัติ ตามที่ระบุไว้ในไฟล์ Manifest ของส่วนเสริม ("รูท" ของกองการ์ดตามบริบทและไม่ตามบริบท)

การส่งคืนการ์ดหลายใบ

ตัวอย่างการ์ดส่วนเสริม

ฟังก์ชันทริกเกอร์ตามบริบทหรือหน้าแรกใช้ในการสร้างและแสดงผลออบเจ็กต์ Card รายการเดียวหรืออาร์เรย์ออบเจ็กต์ Card ที่ UI ของแอปพลิเคชันแสดง

หากมีเพียงการ์ดเดียว ระบบจะเพิ่มการ์ดนั้นลงในกองแบบไม่ตามบริบทหรือตามบริบท และการ์ดรูทจะแสดงใน UI ของแอปพลิเคชันโฮสต์

หากอาร์เรย์ที่แสดงผลมีออบเจ็กต์ Card ที่สร้างขึ้นมากกว่า 1 รายการ แอปพลิเคชันโฮสต์จะแสดงการ์ดใหม่แทน ซึ่งมีรายการส่วนหัวของการ์ดแต่ละใบ เมื่อผู้ใช้คลิกส่วนหัวใดก็ตาม UI จะแสดงการ์ดที่เกี่ยวข้อง

เมื่อผู้ใช้เลือกการ์ดจากรายการ ระบบจะดันการ์ดนั้นลงในกองปัจจุบันและแอปพลิเคชันโฮสต์จะแสดงการ์ดนั้น ปุ่ม จะนําผู้ใช้กลับไปยังรายการส่วนหัวของการ์ด

การจัดเรียงการ์ดแบบ "แบน" นี้อาจได้ผลดีหากส่วนเสริมของคุณไม่จําเป็นต้องมีความต่อเนื่องระหว่างการ์ดที่คุณสร้าง อย่างไรก็ตาม ในกรณีส่วนใหญ่ แนวทางปฏิบัติที่ดีกว่าคือการกําหนดการเปลี่ยนการ์ดโดยตรง และทําให้หน้าแรกและฟังก์ชันทริกเกอร์ตามบริบทแสดงผลออบเจ็กต์การ์ดรายการเดียว

ตัวอย่าง

ต่อไปนี้เป็นตัวอย่างที่แสดงวิธีสร้างการ์ดหลายใบที่มีปุ่มไปยังส่วนต่างๆ การ์ดเหล่านี้สามารถเพิ่มลงในกองที่มีบริบทหรือไม่มีบริบทได้โดยการปッシュการ์ดที่ createNavigationCard() แสดงผลในหรือนอกบริบทหนึ่งๆ

  /**
   *  Create the top-level card, with buttons leading to each of three
   *  'children' cards, as well as buttons to backtrack and return to the
   *  root card of the stack.
   *  @return {Card}
   */
  function createNavigationCard() {
    // Create a button set with actions to navigate to 3 different
    // 'children' cards.
    var buttonSet = CardService.newButtonSet();
    for(var i = 1; i <= 3; i++) {
      buttonSet.addButton(createToCardButton(i));
    }

    // Build the card with all the buttons (two rows)
    var card = CardService.newCardBuilder()
        .setHeader(CardService.newCardHeader().setTitle('Navigation'))
        .addSection(CardService.newCardSection()
            .addWidget(buttonSet)
            .addWidget(buildPreviousAndRootButtonSet()));
    return card.build();
  }

  /**
   *  Create a button that navigates to the specified child card.
   *  @return {TextButton}
   */
  function createToCardButton(id) {
    var action = CardService.newAction()
        .setFunctionName('gotoChildCard')
        .setParameters({'id': id.toString()});
    var button = CardService.newTextButton()
        .setText('Card ' + id)
        .setOnClickAction(action);
    return button;
  }

  /**
   *  Create a ButtonSet with two buttons: one that backtracks to the
   *  last card and another that returns to the original (root) card.
   *  @return {ButtonSet}
   */
  function buildPreviousAndRootButtonSet() {
    var previousButton = CardService.newTextButton()
        .setText('Back')
        .setOnClickAction(CardService.newAction()
            .setFunctionName('gotoPreviousCard'));
    var toRootButton = CardService.newTextButton()
        .setText('To Root')
        .setOnClickAction(CardService.newAction()
            .setFunctionName('gotoRootCard'));

    // Return a new ButtonSet containing these two buttons.
    return CardService.newButtonSet()
        .addButton(previousButton)
        .addButton(toRootButton);
  }

  /**
   *  Create a child card, with buttons leading to each of the other
   *  child cards, and then navigate to it.
   *  @param {Object} e object containing the id of the card to build.
   *  @return {ActionResponse}
   */
  function gotoChildCard(e) {
    var id = parseInt(e.parameters.id);  // Current card ID
    var id2 = (id==3) ? 1 : id + 1;      // 2nd card ID
    var id3 = (id==1) ? 3 : id - 1;      // 3rd card ID
    var title = 'CARD ' + id;

    // Create buttons that go to the other two child cards.
    var buttonSet = CardService.newButtonSet()
      .addButton(createToCardButton(id2))
      .addButton(createToCardButton(id3));

    // Build the child card.
    var card = CardService.newCardBuilder()
        .setHeader(CardService.newCardHeader().setTitle(title))
        .addSection(CardService.newCardSection()
            .addWidget(buttonSet)
            .addWidget(buildPreviousAndRootButtonSet()))
        .build();

    // Create a Navigation object to push the card onto the stack.
    // Return a built ActionResponse that uses the navigation object.
    var nav = CardService.newNavigation().pushCard(card);
    return CardService.newActionResponseBuilder()
        .setNavigation(nav)
        .build();
  }

  /**
   *  Pop a card from the stack.
   *  @return {ActionResponse}
   */
  function gotoPreviousCard() {
    var nav = CardService.newNavigation().popCard();
    return CardService.newActionResponseBuilder()
        .setNavigation(nav)
        .build();
  }

  /**
   *  Return to the initial add-on card.
   *  @return {ActionResponse}
   */
  function gotoRootCard() {
    var nav = CardService.newNavigation().popToRoot();
    return CardService.newActionResponseBuilder()
        .setNavigation(nav)
        .build();
  }