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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. สร้างออบเจ็กต์ Action และเชื่อมโยงกับฟังก์ชัน Callback ที่คุณกำหนด
  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();
  }