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

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

เดิมทีในส่วนเสริมของ 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. ใช้ฟังก์ชันเรียกกลับที่นำทาง ฟังก์ชันนี้ ได้รับออบเจ็กต์เหตุการณ์การกระทํา เป็นอาร์กิวเมนต์ และต้องทําสิ่งต่อไปนี้
    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 ของแอปพลิเคชันโฮสต์จะแสดงบัตรนั้น

หากอาร์เรย์ที่ส่งคืนมีออบเจ็กต์ที่สร้างไว้ล่วงหน้ามากกว่า 1 รายการ Card แอปพลิเคชันโฮสต์จะแสดงการ์ดใหม่แทน ซึ่งมีการ์ดส่วนหัวของแต่ละการ์ด เมื่อผู้ใช้คลิกส่วนหัวใดส่วนหัวหนึ่ง 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();
  }