Di chuyển thẻ

Hầu hết tiện ích bổ sung dựa trên thẻ được xây dựng bằng cách sử dụng nhiều thẻ đại diện cho các "trang" khác nhau của giao diện tiện ích bổ sung. Để có trải nghiệm người dùng hiệu quả, bạn nên sử dụng cách điều hướng đơn giản và tự nhiên giữa các thẻ trong tiện ích bổ sung.

Ban đầu trong tiện ích bổ sung của Gmail, quá trình chuyển đổi giữa các thẻ của giao diện người dùng được xử lý bằng cách đẩy và bật các thẻ lên và ra từ một ngăn xếp thẻ, trong đó thẻ trên cùng của ngăn xếp được Gmail hiển thị.

Di chuyển thẻ trên trang chủ

Tiện ích bổ sung Google Workspace giới thiệu trang chủ và thẻ không theo ngữ cảnh. Để phù hợp với thẻ theo ngữ cảnh và thẻ không theo ngữ cảnh, Tiện ích bổ sung của Google Workspace có một ngăn xếp thẻ nội bộ cho mỗi thẻ. Khi bạn mở một tiện ích bổ sung trong một máy chủ, homepageTrigger tương ứng sẽ kích hoạt để tạo thẻ trang chủ đầu tiên trên ngăn xếp (thẻ "trang chủ" màu xanh dương đậm trong sơ đồ bên dưới). Nếu homepageTrigger không được xác định, thì một thẻ mặc định sẽ được tạo, hiển thị và đẩy vào ngăn xếp không theo ngữ cảnh. Thẻ đầu tiên là thẻ gốc.

Tiện ích bổ sung của bạn có thể tạo thêm các thẻ không theo ngữ cảnh và đẩy các thẻ đó vào ngăn xếp (các "thẻ được đẩy" màu xanh dương trong sơ đồ) khi người dùng di chuyển qua các tiện ích bổ sung của bạn. Giao diện người dùng của tiện ích bổ sung hiển thị thẻ trên cùng trong ngăn xếp, vì vậy, việc đẩy thẻ mới vào ngăn xếp sẽ thay đổi màn hình và bật thẻ ra khỏi ngăn xếp sẽ trả màn hình về các thẻ trước.

Nếu tiện ích bổ sung của bạn có trình kích hoạt theo ngữ cảnh đã xác định, thì khi người dùng nhập ngữ cảnh đó, trình kích hoạt sẽ kích hoạt. Hàm kích hoạt tạo thẻ ngữ cảnh, nhưng màn hình giao diện người dùng được cập nhật dựa trên DisplayStyle của thẻ mới:

  • Nếu DisplayStyleREPLACE (mặc định), thì thẻ ngữ cảnh (thẻ "theo ngữ cảnh" màu cam đậm trong sơ đồ) sẽ thay thế thẻ hiện đang hiển thị. Thao tác này sẽ bắt đầu hiệu quả một ngăn xếp thẻ theo ngữ cảnh mới ở đầu ngăn xếp thẻ không theo ngữ cảnh và thẻ theo ngữ cảnh này là thẻ gốc của ngăn xếp theo ngữ cảnh.
  • Nếu DisplayStylePEEK, thì giao diện người dùng sẽ tạo một tiêu đề hiển thị nhanh xuất hiện ở cuối thanh bên của tiện ích bổ sung, phủ lên thẻ hiện tại. Tiêu đề xem trước cho thấy tiêu đề của thẻ mới và cung cấp các nút điều khiển cho người dùng để họ quyết định có xem thẻ mới hay không. Nếu họ nhấp vào nút View (Xem), thẻ này sẽ thay thế thẻ hiện tại (như mô tả ở trên bằng REPLACE).

Bạn có thể tạo thêm các thẻ theo ngữ cảnh và đẩy các thẻ đó vào ngăn xếp (các "thẻ được đẩy" màu vàng trong sơ đồ). Việc cập nhật ngăn xếp thẻ sẽ thay đổi giao diện người dùng của tiện ích bổ sung để hiển thị thẻ ở trên cùng. Nếu người dùng rời khỏi một ngữ cảnh, thì các thẻ ngữ cảnh trên ngăn xếp sẽ bị xoá và màn hình sẽ cập nhật thành thẻ hoặc trang chủ không theo ngữ cảnh ở trên cùng.

Nếu người dùng nhập một ngữ cảnh mà tiện ích bổ sung của bạn không xác định trình kích hoạt theo ngữ cảnh, thì sẽ không có thẻ mới nào được tạo và thẻ hiện tại vẫn hiển thị.

Các thao tác Navigation được mô tả dưới đây chỉ hoạt động trên các thẻ có cùng ngữ cảnh; ví dụ: popToRoot() từ bên trong thẻ theo ngữ cảnh chỉ làm bật tất cả các thẻ theo ngữ cảnh khác và sẽ không ảnh hưởng đến thẻ trang chủ.

Ngược lại, nút luôn có sẵn để người dùng di chuyển từ thẻ theo ngữ cảnh đến thẻ không theo ngữ cảnh.

Bạn có thể tạo hiệu ứng chuyển đổi giữa các thẻ bằng cách thêm hoặc xoá thẻ khỏi ngăn xếp thẻ. Lớp Navigation cung cấp các hàm để đẩy và bật thẻ ra khỏi ngăn xếp. Để xây dựng thao tác thẻ hiệu quả, bạn sẽ định cấu hình các tiện ích để sử dụng các thao tác điều hướng. Bạn có thể đẩy hoặc bật nhiều thẻ cùng lúc, nhưng không thể xoá thẻ trang chủ ban đầu được đẩy đầu tiên vào ngăn xếp khi tiện ích bổ sung khởi động.

Để chuyển đến một thẻ mới nhằm phản hồi hoạt động tương tác của người dùng với một tiện ích, hãy làm theo các bước sau:

  1. Tạo một đối tượng Action và liên kết đối tượng đó với một hàm callback mà bạn đã xác định.
  2. Hãy gọi hàm trình xử lý tiện ích thích hợp của tiện ích để đặt Action trên tiện ích đó.
  3. Triển khai hàm callback thực hiện việc điều hướng. Hàm này được cấp một đối tượng sự kiện hành động làm đối số và phải thực hiện những việc sau:
    1. Tạo đối tượng Navigation để xác định việc thay đổi thẻ. Một đối tượng Navigation có thể chứa nhiều bước điều hướng được thực hiện theo thứ tự được thêm vào đối tượng.
    2. Tạo đối tượng ActionResponse bằng cách sử dụng lớp ActionResponseBuilder và đối tượng Navigation.
    3. Trả về ActionResponse đã tạo.

Khi tạo các thành phần điều khiển điều hướng, bạn sẽ sử dụng các hàm đối tượng Navigation sau:

Chức năng Mô tả
Navigation.pushCard(Card) Đẩy thẻ vào ngăn xếp hiện tại. Để làm được điều này, bạn phải hoàn toàn tạo thẻ trước.
Navigation.popCard() Xoá một thẻ khỏi đầu ngăn xếp. Tương đương với việc nhấp vào mũi tên quay lại trong hàng tiêu đề của tiện ích bổ sung. Thao tác này sẽ không xoá các thẻ gốc.
Navigation.popToRoot() Xoá tất cả thẻ khỏi ngăn xếp, ngoại trừ thẻ gốc. Về cơ bản, việc đặt lại ngăn xếp thẻ đó.
Navigation.popToNamedCard(String) Bật các thẻ ra khỏi ngăn xếp cho đến khi gặp một thẻ có tên cụ thể hoặc thẻ gốc của ngăn xếp. Bạn có thể chỉ định tên cho thẻ bằng hàm CardBuilder.setName(String).
Navigation.updateCard(Card) Thực hiện thay thế tại chỗ của thẻ hiện tại, làm mới màn hình của thẻ trong giao diện người dùng.

Nếu một hoạt động tương tác hoặc sự kiện của người dùng dẫn đến việc hiển thị lại thẻ trong cùng một ngữ cảnh, hãy dùng Navigation.pushCard(), Navigation.popCard() và các phương thức Navigation.updateCard() để thay thế thẻ hiện có. Nếu một hoạt động tương tác hoặc sự kiện của người dùng khiến thẻ hiển thị lại trong ngữ cảnh khác, hãy sử dụng ActionResponseBuilder.setStateChanged() để buộc thực thi lại tiện ích bổ sung trong những ngữ cảnh đó.

Sau đây là các ví dụ về cách điều hướng:

  • Nếu một lượt tương tác hoặc sự kiện làm thay đổi trạng thái của thẻ hiện tại (ví dụ: thêm một việc cần làm vào danh sách việc cần làm), hãy sử dụng updateCard().
  • Nếu một lượt tương tác hoặc sự kiện cung cấp thêm thông tin chi tiết hoặc nhắc người dùng thực hiện thêm hành động (ví dụ: nhấp vào tiêu đề của một mục để xem thêm thông tin chi tiết hoặc nhấn nút để tạo sự kiện mới trên Lịch), hãy sử dụng pushCard() để hiển thị trang mới trong khi cho phép người dùng thoát khỏi trang mới bằng nút quay lại.
  • Nếu một lượt tương tác hoặc sự kiện cập nhật trạng thái trong thẻ trước đó (ví dụ: cập nhật tiêu đề của một mặt hàng từ chế độ xem chi tiết), hãy sử dụng popCard(), popCard(), pushCard(previous)pushCard(current) để cập nhật thẻ trước đó và thẻ hiện tại.

Làm mới thẻ

Tiện ích bổ sung của Google Workspace cho phép người dùng làm mới thẻ của bạn bằng cách chạy lại chức năng kích hoạt Apps Script đã đăng ký trong tệp kê khai của bạn. Người dùng kích hoạt quá trình làm mới này thông qua một mục trong trình đơn tiện ích bổ sung:

Thanh bên của Tiện ích bổ sung của Google Workspace

Thao tác này được tự động thêm vào các thẻ do các hàm kích hoạt homepageTrigger hoặc contextualTrigger tạo, như được chỉ định trong tệp kê khai của tiện ích bổ sung ('gốc' của ngăn xếp thẻ theo ngữ cảnh và không theo ngữ cảnh).

Trả lại nhiều thẻ

Thẻ tiện ích bổ sung mẫu

Các hàm kích hoạt theo ngữ cảnh hoặc trang chủ được dùng để tạo và trả về một đối tượng Card duy nhất hoặc một mảng các đối tượng Card mà giao diện người dùng của ứng dụng hiển thị.

Nếu chỉ có một thẻ, thẻ đó sẽ được thêm vào ngăn xếp không theo ngữ cảnh hoặc theo ngữ cảnh dưới dạng thẻ gốc và giao diện người dùng của ứng dụng lưu trữ sẽ hiển thị thẻ đó.

Nếu mảng được trả về bao gồm nhiều đối tượng Card đã tạo, thì ứng dụng lưu trữ sẽ hiển thị một thẻ mới, trong đó có chứa danh sách tiêu đề của từng thẻ. Khi người dùng nhấp vào bất kỳ tiêu đề nào trong số đó, giao diện người dùng sẽ hiển thị thẻ tương ứng.

Khi người dùng chọn một thẻ trong danh sách, thẻ đó sẽ được đẩy vào ngăn xếp hiện tại và ứng dụng lưu trữ sẽ hiển thị thẻ đó. Nút sẽ đưa người dùng trở về danh sách tiêu đề thẻ.

Cách sắp xếp thẻ "phẳng" này có thể hoạt động hiệu quả nếu tiện ích bổ sung không cần bất kỳ chuyển đổi nào giữa các thẻ mà bạn tạo. Tuy nhiên, trong hầu hết các trường hợp, bạn nên xác định trực tiếp quá trình chuyển đổi thẻ và thiết lập trang chủ cũng như các hàm kích hoạt theo ngữ cảnh trả về một đối tượng thẻ duy nhất.

Ví dụ:

Dưới đây là ví dụ cho thấy cách tạo một số thẻ bằng các nút điều hướng chuyển đổi giữa các thẻ đó. Bạn có thể thêm các thẻ này vào ngăn xếp theo bối cảnh hoặc không theo bối cảnh bằng cách đẩy thẻ mà createNavigationCard() trả về vào trong hoặc bên ngoài một ngữ cảnh cụ thể.

  /**
   *  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();
  }