بیشتر افزونههای مبتنی بر کارت با استفاده از چندین کارت ساخته میشوند که نشاندهندهی «صفحات» مختلف رابط افزونه هستند. برای داشتن یک تجربه کاربری مؤثر، باید از پیمایش ساده و طبیعی بین کارتها در افزونه خود استفاده کنید.
در ابتدا در افزونههای جیمیل، انتقال بین کارتهای مختلف رابط کاربری با فشار دادن و بالا آوردن کارتها به و از یک دسته کارت انجام میشد، و کارت بالایی دسته توسط جیمیل نمایش داده میشد.

افزونههای Google Workspace صفحات اصلی و کارتهای غیرمتنی را معرفی میکنند. برای تطبیق با کارتهای متنی و غیرمتنی، افزونههای Google Workspace برای هر کدام یک پشته کارت داخلی دارند. وقتی یک افزونه در یک میزبان باز میشود، homepageTrigger مربوطه فعال میشود تا اولین کارت صفحه اصلی را روی پشته ایجاد کند (کارت "صفحه اصلی" آبی تیره در نمودار زیر). اگر یک homepageTrigger تعریف نشده باشد، یک کارت پیشفرض ایجاد، نمایش داده و به پشته غیرمتنی منتقل میشود. این کارت اول، یک کارت ریشه است.
افزونه شما میتواند کارتهای غیرمرتبط بیشتری ایجاد کند و همزمان با پیمایش کاربر در افزونه، آنها را به پشته (کارتهای آبی رنگ «پوشانده شده» در نمودار) منتقل کند. رابط کاربری افزونه، کارت بالایی را در پشته نمایش میدهد، بنابراین انتقال کارتهای جدید به پشته، نمایش را تغییر میدهد و برداشتن کارتها از پشته، نمایش کارتهای قبلی را برمیگرداند.
اگر افزونه شما یک تریگر زمینهای تعریفشده داشته باشد، وقتی کاربر وارد آن زمینه میشود، تریگر فعال میشود. تابع تریگر، کارت زمینهای را میسازد، اما نمایش رابط کاربری بر اساس DisplayStyle کارت جدید بهروزرسانی میشود:
- اگر
DisplayStyleREPLACE(پیشفرض) باشد، کارت متنی (کارت «متنی» نارنجی تیره در نمودار) جایگزین کارت نمایش داده شده فعلی میشود. این کار عملاً یک پشته کارت متنی جدید را روی پشته کارت غیر متنی شروع میکند و این کارت متنی، کارت ریشه پشته متنی است. - اگر
DisplayStylePEEKباشد، رابط کاربری یک سربرگ نمایشدهنده ایجاد میکند که در پایین نوار کناری افزونه ظاهر میشود و کارت فعلی را میپوشاند. سربرگ نمایشدهنده، عنوان کارت جدید را نشان میدهد و کنترلهای دکمه کاربر را فراهم میکند که به آنها اجازه میدهد تصمیم بگیرند که آیا کارت جدید را مشاهده کنند یا خیر. اگر کاربر روی دکمه View کلیک کند، کارت جایگزین کارت فعلی میشود (همانطور که در بالا باREPLACEتوضیح داده شد).
میتوانید کارتهای زمینهای بیشتری ایجاد کنید و آنها را روی پشته (کارتهای زرد رنگ «پوشانده شده» در نمودار) قرار دهید. بهروزرسانی پشته کارت، رابط کاربری افزونه را تغییر میدهد تا بالاترین کارت را نمایش دهد. اگر کاربر یک زمینه را ترک کند، کارتهای زمینهای روی پشته حذف میشوند و نمایش به بالاترین کارت غیر زمینهای یا صفحه اصلی بهروزرسانی میشود.
اگر کاربر وارد زمینهای شود که افزونه شما برای آن محرک زمینهای تعریف نکرده باشد، کارت جدیدی ایجاد نمیشود و کارت فعلی نمایش داده میشود.
اقدامات Navigation شرح داده شده در زیر فقط روی کارتهایی از همان زمینه عمل میکنند؛ برای مثال، popToRoot() از درون یک کارت زمینهای، فقط تمام کارتهای زمینهای دیگر را نمایش میدهد و روی کارتهای صفحه اصلی تأثیری نخواهد گذاشت.
در مقابل، دکمه همیشه برای کاربر در دسترس است تا از کارتهای متنی شما به کارتهای غیر متنی شما حرکت کند.
روشهای ناوبری
شما میتوانید با اضافه کردن یا حذف کارتها از دسته کارتها، بین کارتها انتقال ایجاد کنید. کلاس Navigation توابعی برای اضافه کردن و حذف کارتها از دستهها ارائه میدهد. برای ایجاد ناوبری مؤثر کارت، ویجتهای خود را برای استفاده از اقدامات ناوبری پیکربندی میکنید. میتوانید چندین کارت را همزمان اضافه یا حذف کنید، اما نمیتوانید کارت صفحه اصلی اولیه را که برای اولین بار هنگام شروع افزونه به دسته کارتها اضافه میشود، حذف کنید.
برای رفتن به یک کارت جدید در پاسخ به تعامل کاربر با یک ویجت، این مراحل را دنبال کنید:
- یک شیء
Actionایجاد کنید و آن را با یک تابع فراخوانی که تعریف میکنید، مرتبط کنید. - تابع مدیریت ویجت مناسب ویجت را فراخوانی کنید تا
Actionرا روی آن ویجت تنظیم کنید. - تابع فراخوانی که ناوبری را انجام میدهد، پیادهسازی کنید. به این تابع یک شیء رویداد اکشن به عنوان آرگومان داده میشود و باید موارد زیر را انجام دهد:
- یک شیء
Navigationبرای تعریف تغییر کارت ایجاد کنید. یک شیءNavigationمیتواند شامل چندین مرحله ناوبری باشد که به ترتیب اضافه شدن به شیء انجام میشوند. - با استفاده از کلاس
ActionResponseBuilderو شیءNavigation، یک شیءActionResponseبسازید. -
ActionResponseساخته شده را برمیگرداند.
- یک شیء
هنگام ساخت کنترلهای ناوبری، از توابع شیء Navigation زیر استفاده میکنید:
| عملکرد | توضیحات |
|---|---|
Navigation.pushCard(Card) | یک کارت را به دسته کارتهای فعلی اضافه میکند. این کار مستلزم ساخت کامل کارت است. |
Navigation.popCard() | یک کارت از بالای دسته کارتها حذف میکند. معادل کلیک روی فلش برگشت در ردیف سربرگ افزونه است. این کار کارتهای ریشه را حذف نمیکند. |
Navigation.popToRoot() | تمام کارتها را به جز کارت ریشه از دسته کارتها حذف میکند. اساساً دسته کارتها را از نو تنظیم میکند. |
Navigation.popToNamedCard(String) | کارتها را از پشته بیرون میکشد تا به کارتی با نام داده شده یا کارت ریشه پشته برسد. میتوانید با استفاده از تابع CardBuilder.setName(String) به کارتها نام اختصاص دهید. |
Navigation.updateCard(Card) | یک جایگزینی درجا برای کارت فعلی انجام میدهد و نمایش آن را در رابط کاربری بهروزرسانی میکند. |
بهترین شیوههای ناوبری
اگر یک تعامل یا رویداد کاربر باید منجر به رندر مجدد کارتها در همان زمینه شود، از متدهای Navigation.pushCard() ، Navigation.popCard() و Navigation.updateCard() برای جایگزینی کارتهای موجود استفاده کنید. اگر یک تعامل یا رویداد کاربر باید منجر به رندر مجدد کارتها در یک زمینه متفاوت شود، از ActionResponseBuilder.setStateChanged() برای اجرای مجدد افزونه خود در آن زمینهها استفاده کنید.
نمونههایی از ناوبری در زیر آمده است:
- اگر یک تعامل یا رویداد وضعیت کارت فعلی را تغییر دهد (برای مثال، اضافه کردن یک وظیفه به لیست وظایف)، از
updateCard()استفاده کنید. - اگر یک تعامل یا رویداد جزئیات بیشتری ارائه میدهد یا کاربر را به اقدام دیگری ترغیب میکند (برای مثال، کلیک روی عنوان یک آیتم برای دیدن جزئیات بیشتر، یا فشار دادن یک دکمه برای ایجاد یک رویداد تقویم جدید)، از
pushCard()برای نمایش صفحه جدید استفاده کنید و در عین حال به کاربر اجازه دهید با استفاده از دکمه بازگشت از صفحه جدید خارج شود. - اگر یک تعامل یا رویداد، وضعیت یک کارت قبلی را بهروزرسانی کند (برای مثال، بهروزرسانی عنوان یک آیتم از طریق نمای جزئیات)، از چیزی مانند
popCard()،popCard()،pushCard(previous)وpushCard(current)برای بهروزرسانی کارت قبلی و کارت فعلی استفاده کنید.
کارتهای تازهسازیشده
افزونههای Google Workspace به کاربران این امکان را میدهند که با اجرای مجدد تابع فعالسازی Apps Script که در مانیفست شما ثبت شده است، کارت شما را بهروزرسانی کنند. کاربران این بهروزرسانی را از طریق یک آیتم منوی افزونه فعال میکنند:

این عمل به طور خودکار به کارتهای تولید شده توسط توابع محرک homepageTrigger یا contextualTrigger اضافه میشود، همانطور که در فایل مانیفست افزونه شما ("ریشههای" پشتههای کارتهای متنی و غیر متنی) مشخص شده است.
برگرداندن چندین کارت
توابع تریگر صفحه اصلی یا متنی برای ساخت و بازگرداندن یک شیء Card یا آرایهای از اشیاء Card که رابط کاربری برنامه نمایش میدهد، استفاده میشوند.
اگر فقط یک کارت وجود داشته باشد، به عنوان کارت ریشه به پشته غیرمتنی یا متنی اضافه میشود و رابط کاربری برنامه میزبان آن را نمایش میدهد.
اگر آرایهی برگردانده شده شامل بیش از یک شیء Card ساخته شده باشد، برنامهی میزبان به جای آن یک کارت جدید نمایش میدهد که شامل لیستی از سربرگ هر کارت است. وقتی کاربر روی هر یک از آن سربرگها کلیک میکند، رابط کاربری کارت مربوطه را نمایش میدهد.
وقتی کاربر یک کارت را از لیست انتخاب میکند، آن کارت به پشته فعلی اضافه میشود و برنامه میزبان آن را نمایش میدهد. دکمه کاربر را به لیست سربرگ کارتها برمیگرداند.
این چیدمان کارت «مسطح» میتواند در صورتی که افزونه شما نیازی به انتقال بین کارتهایی که ایجاد میکنید نداشته باشد، به خوبی کار کند. با این حال، در بیشتر موارد، بهتر است که انتقال کارتها را مستقیماً تعریف کنید و صفحه اصلی و توابع تریگر متنی خود را طوری تنظیم کنید که یک شیء کارت واحد را برگردانند.
مثال
در اینجا مثالی آورده شده است که نحوه ساخت چندین کارت با دکمههای ناوبری که بین آنها جابجا میشوند را نشان میدهد. این کارتها را میتوان با قرار دادن کارت برگردانده شده توسط 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();
}