多页面流程
简介
此示例演示了如何在 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>
我们已将垂直步进器封装在可提交的表单中。提交后,用户将在 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 类(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 上编辑示例