AMP
  • 網站

多頁流程

簡介

此範例示範如何在 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>
步驟 1
這是一些內容...
<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-completestep-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>

我們已將垂直步驟器封裝在可提交的表單中。使用者在 Submit 後會看到他們的選取項目位於網址參數字串中。

以下是完整範例

您最喜歡的動物是什麼?

 
<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 類別 (activenextprevious) 在不同頁面之間滑動

  .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 上編輯範例