多页面流程
简介
此示例演示了在 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 上编辑示例-
作者: @sebastianbenz