多頁流程
簡介
此範例示範如何在 AMP 中實作多步驟流程的不同方法。這些方法可用於結帳流程、註冊或問卷調查。
設定
我們使用 amp-bind
來協調頁面轉換...
<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>
... 以及 amp-selector
來實作簡易問卷調查。
<script async custom-element="amp-selector" src="https://cdn.ampproject.org/v0/amp-selector-0.1.js"></script>
簡易對話方塊
我們使用隱含狀態變數 currentPage
來追蹤目前的檢視畫面。檢視畫面會依其出現順序以數字 (從 0
開始) 識別。檢視畫面狀態會使用 AMP 的 hidden
屬性繫結至每個檢視畫面
<section [hidden]="currentPage > 0"> ... </section>
...對於初始隱藏的檢視畫面,我們會新增 hidden
屬性作為預設值
<section hidden [hidden]="currentPage != 1"> ... </section>
我們會更新 currentPage
變數,以在對話方塊中向前推進。在此範例中,我們使用 AMP.pushState(...)
而非 AMP.setState(...)
。AMP.pushState(...)
會將新項目推送至瀏覽器歷程記錄堆疊,讓使用者能夠在對話方塊中使用瀏覽器的返回按鈕向後瀏覽
<button on="tap:AMP.pushState({ currentPage: currentPage + 1 })"> next </button>
<div class="stepper simple">
<section [hidden]="currentPage > 0">
<div class="top-bar">
Step 1
</div>
<div class="content">Here is some content ...</div>
<div class="bottom-bar">
<div class="step-dots">
<i class="step-dot active"></i>
<i class="step-dot"></i>
<i class="step-dot"></i>
</div>
<button on="tap:AMP.pushState({ currentPage: currentPage + 1 })" class="button-next">next</button>
</div>
</section>
<section hidden [hidden]="currentPage != 1">
<div class="top-bar">
Step 2
</div>
<div class="content">Here is some more content ...</div>
<div class="bottom-bar">
<button class="button-prev" on="tap:AMP.pushState({ currentPage: currentPage - 1 })">back</button>
<div class="step-dots">
<i class="step-dot active"></i>
<i class="step-dot active"></i>
<i class="step-dot"></i>
</div>
<button on="tap:AMP.pushState({ currentPage: currentPage + 1 })" class="button-next">next</button>
</div>
</section>
<section hidden [hidden]="currentPage != 2">
<div class="top-bar">
Step 3
</div>
<div class="content">Done!</div>
<div class="bottom-bar">
<button class="button-prev" on="tap:AMP.pushState({ currentPage: currentPage - 1 })">back</button>
<div class="step-dots">
<i class="step-dot active"></i>
<i class="step-dot active"></i>
<i class="step-dot active"></i>
</div>
</div>
</section>
</div>
垂直步進器
如果步驟彼此相依,則垂直步進器非常適合。步進器的實作方式與第一個範例類似,都是使用 currentStep
變數來追蹤目前作用中的步驟。我們另外定義了步驟標題按鈕,該按鈕會持續顯示,並顯示目前步驟的狀態。標題需要反映三種不同的狀態 (作用中、已完成、已停用)。為了避免 amp-bind 運算式過於複雜,這三種狀態會分成三個不同的繫結
- 如果目前的步驟為作用中,則標題類別會更新。
- 如果前一個步驟尚未完成,則標題會取得
disabled
屬性 - 巢狀圖示的類別會根據步驟是否已完成而設為
step-complete
或step-incomplete
。
按一下標題會前往對應的步驟 (如果已可前往)
<button class="step-title" [class]="currentStep != 1 ? 'step-title' : 'step-title step-active'" disabled [disabled]="!animalSelected" on="tap:AMP.pushState({ currentStep: 1 })"> <i class="step-incomplete" [class]="colorSelected ? 'step-complete' : 'step-incomplete'" data-step-nr="2"></i> Color </button>
根據預設,「繼續」按鈕會停用。只有在步驟完成時 (在此情況下,選取項目時),才會啟用該按鈕
<button disabled [disabled]="!animalSelected" on="tap:AMP.pushState({ currentStep: currentStep + 1 })"> continue </button>
我們已將垂直步進器放在可提交的表單中。使用者在「提交」後,會看到其選取項目位於網址參數字串中。
以下是完整範例
<form class="multistep-form" method="get" action="#" target="_top">
<div class="stepper vertical">
<button class="step-title step-active" [class]="currentStep > 0 ? 'step-title' : 'step-title step-active'" on="tap:AMP.pushState({ currentStep: 0 })">
<i class="step-incomplete" [class]="animalSelected ? 'step-complete' : 'step-incomplete'" data-step-nr="1"></i>
Animal
</button>
<section [hidden]="currentStep > 0">
<div class="content">
<p>What's your favorite animal?</p>
<amp-selector on="select:AMP.setState({animalSelected: true})" class="poll" name="animal-poll">
<div option="cat">Cat</div>
<div option="dog">Dog</div>
<div option="horse">Horse</div>
</amp-selector>
<button disabled [disabled]="!animalSelected" on="tap:AMP.pushState({ currentStep: currentStep + 1 })">
continue
</button>
</div>
</section>
<button class="step-title" [class]="currentStep != 1 ? 'step-title' : 'step-title step-active'" disabled [disabled]="!animalSelected" on="tap:AMP.pushState({ currentStep: 1 })">
<i class="step-incomplete" [class]="colorSelected ? 'step-complete' : 'step-incomplete'" data-step-nr="2"></i>
Color
</button>
<section hidden [hidden]="currentStep != 1">
<div class="content">
<p>What's your favorite color?</p>
<amp-selector on="select:AMP.setState({colorSelected: true})" class="poll" name="color-poll">
<div option="blue">Blue</div>
<div option="green">Green</div>
<div option="yellow">Yellow</div>
</amp-selector>
<button disabled [disabled]="!colorSelected" on="tap:AMP.pushState({ currentStep: currentStep + 1 })">
continue
</button>
</div>
</section>
<button class="step-title" [class]="currentStep != 2 ? 'step-title' : 'step-title step-active'" disabled [disabled]="!colorSelected" on="tap:AMP.pushState({ currentStep: 2 })">
<i class="step-incomplete" [class]="fruitSelected ? 'step-complete' : 'step-incomplete'" data-step-nr="3"></i>
Fruit
</button>
<section hidden [hidden]="currentStep != 2">
<div class="content">
<p>What's your favorite fruit?</p>
<amp-selector on="select:AMP.setState({fruitSelected: true})" class="poll" name="fruit-poll">
<div option="apple">Apple</div>
<div option="banana">Banana</div>
<div option="cheery">Cherry</div>
</amp-selector>
<button disabled [disabled]="!fruitSelected" on="tap:AMP.pushState({ currentStep: currentStep + 1 })">
continue
</button>
</div>
</section>
</div>
<input type="submit" value="Submit">
</form>
具有滑動動畫的步進器
此範例示範簡易滑動動畫,以視覺化呈現對話方塊進度。基本方法與前兩個範例相同:變數會追蹤目前的頁面。唯一的差異在於,這裡我們無法使用 hidden
屬性,因為我們想要在不同頁面之間轉換。hidden
屬性使用 display: none
,這無法在 CSS 中製作動畫。相反地,我們使用三個不同的 CSS 類別 (active
、next
和 previous
) 在不同頁面之間滑動
.page.active { transform: translateX(0%); pointer-events: auto; } .page:not(.active) { opacity: 0.5; pointer-events: none; } .page.next { transform: translateX(100%); } .page.previous { transform: translateX(-100%); }
針對每個頁面,我們會根據頁面索引是較小、相同或較大來指派相符的類別
<section class="page next" [class]="slidingStepperPage < 1 ? 'page next' : (slidingStepperPage > 1 ? 'page previous' : 'page active')"> ...</section>
為了避免透過鍵盤焦點意外顯示隱藏的步驟,我們需要確保明確停用所有輸入元素
在隱藏的步驟中,例如:
<input type="text" value="" name="password" disabled [disabled]="slidingStepperPage != 1" ...>
我們使用 amp-state 變數 email
在兩個步驟之間同步輸入的電子郵件地址
<input type="email" value="" name="email" on="input-debounced: AMP.setState({ email: event.value })" ...> ... <button class="back" [text]="email" ...></button>
以下是完整範例
<form class="stepper sliding" method="post" action-xhr="/documentation/examples/api/submit-form-input-text-xhr" novalidate on="submit: AMP.setState({ slidingStepperPage: 2 });
submit-success: AMP.setState({ slidingStepperPage: 3 });
submit-error: AMP.setState({ slidingStepperPage: 4 });
">
<section class="page active" [class]="slidingStepperPage > 0 ? 'page previous' : 'page active'">
<h3>Sign in</h3>
<div class="input">
<input type="email" value name="email" autocomplete="email" id="id1" placeholder="Enter your Email" on="input-debounced: AMP.setState({ email: event.value })">
<label for="ip1" aria-hidden="true">
Enter your Email
</label>
</div>
<button type="button" on="tap:AMP.pushState({ slidingStepperPage: slidingStepperPage + 1 })" disabled [disabled]="!email">next</button>
</section>
<section class="page next" [class]="slidingStepperPage < 1 ? 'page next' :
(slidingStepperPage > 1 ? 'page previous' : 'page active')">
<h3>Welcome</h3>
<button class="back" [text]="email" on="tap:AMP.pushState({ slidingStepperPage: slidingStepperPage - 1 })" disabled [disabled]="slidingStepperPage != 1" type="button"></button>
<div class="input">
<input type="password" value name="password" id="id2" placeholder="Enter your Password" disabled [disabled]="slidingStepperPage != 1" on="input-debounced: AMP.setState({ password: event.value })">
<label for="ip2" aria-hidden="true">
Enter your Password
</label>
</div>
<button disabled [disabled]="slidingStepperPage != 1 || !password" type="submit">submit</button>
</section>
<section class="page next" [class]="slidingStepperPage < 2 ? 'page next' :
(slidingStepperPage > 2 ? 'page previous' : 'page active')">
<p>Submitting ...</p>
</section>
<section class="page next" [class]="slidingStepperPage < 3 ? 'page next' :
(slidingStepperPage > 3 ? 'page previous' : 'page active')">
<h3>Success</h3>
<p>You did it!</p>
</section>
<section class="page next" [class]="slidingStepperPage < 4 ? 'page next' :
(slidingStepperPage > 4 ? 'page previous' : 'page active')">
<h3>Something went wrong. </h3>
<button on="tap:AMP.setState({ slidingStepperPage: 0 })" type="button">Try again</button>
</section>
</form>
如果本頁面的說明未涵蓋您的所有問題,請隨時與其他 AMP 使用者聯絡,討論您的確切使用案例。
前往 Stack Overflow 有無法解釋的功能?AMP 專案強烈鼓勵您參與和貢獻!我們希望您能成為我們開放原始碼社群的長期參與者,但我們也歡迎您針對您特別關注的問題做出一次性貢獻。
在 GitHub 上編輯範例-
作者: @sebastianbenz