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>

我们已将垂直步进器封装在可提交的表单中。在 提交 后,用户将看到他们的选择位于 URL 参数字符串中。

这是完整的示例

你最喜欢的动物是什么?

 
<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 上编辑示例