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