使用UI Router实现AngularJS 多步骤表单(渣译)
原文地址: https://scotch.io/tutorials/angularjs-multi-step-form-using-ui-router
今天,我们将使用 AngularJS,UIRouter 和 AngularJS ngAnimate 模块去创建一个动态的多步骤表单。这项技术可以被用于大型表单。我们也可以看到该技术被用于 Web 上的很多地方。像购物车,注册表单,入职流程,等已经通过使用多步骤表单形式提高用户舒适度的在线表单。下面就是我们所要创建的:
UI Router 具有的如下功能:
嵌套状态 ( nested states ) 并且每个状态对应不同的视图的功能, 利用这些功能,我们能很容易的制作一个多步骤表单。为了快速理解它的好处和 UI Router 是如何工作,请查阅我们的其它文章: AngularJS Routing Using UI-Router 。让我们言归正传,开始创建我们精彩的表单!
建立工程
我们将为应用使用简单的结构,需要一个 layout 文件,表单每一部分的视图文件,一个样式表和保存所有 Angular 代码的 JavaScript 文件。
下面是我们的应用程序的文件。创建这些文件,我们将开始填写他们。
- index.html
- form.html
- form-profile.html
- form-interests.html
- form-payment.html
- app.js
- style.css
每个 form-____.html 的文件将会被作为嵌套视图用于表单中,这些是将要创建的表单的每一部分。
Layout/Template 文件 (index.html)
让我们开始工程,使用 index.html 作为 main 文件,在 index.html 导入所有的资源( AngularJS, ngAnimate, UI Router, JavaScript 脚本和样式 )并放置 ui-view 告诉 UI Router 在哪里插入视图,我们也会使用 Bootstrap 快速设置样式。
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- CSS -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootswatch/3.1.1/darkly/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
<!-- JS -->
<!-- load angular, nganimate, and ui-router -->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular-animate.min.js"></script>
<script src="app.js"></script>
</head>
<!-- apply our angular app -->
<body ng-app="formApp">
<div class="container">
<!-- views will be injected here -->
<div ui-view></div>
</div>
</body>
</html>
随着所有的文件装载完毕,让我们进入 app.js , 开始创建我们的 Angular 应用和基于状态的路由。注意 formApp 是如何应用到 body 上的。
构建 Angular 应用 ( app.js )
我们将会创建我们的应用和路由。对大型应用,你会将 angular 应用,路由和控制器分开放入它们各自单独的模块中,但是对于我们的目标,我们会将它们放在一块。
`````` app.js```
// app.js
// create our angular app and inject ngAnimate and ui-router
// =============================================================================
angular.module('formApp', ['ngAnimate', 'ui.router'])
// configuring our routes
// =============================================================================
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
// route to show our basic form (/form)
.state('form', {
url: '/form',
templateUrl: 'form.html',
controller: 'formController'
})
// nested states
// each of these sections will have their own view
// url will be nested (/form/profile)
.state('form.profile', {
url: '/profile',
templateUrl: 'form-profile.html'
})
// url will be /form/interests
.state('form.interests', {
url: '/interests',
templateUrl: 'form-interests.html'
})
// url will be /form/payment
.state('form.payment', {
url: '/payment',
templateUrl: 'form-payment.html'
});
// catch all route
// send users to the form page
$urlRouterProvider.otherwise('/form/profile');
})
// our controller for the form
// =============================================================================
.controller('formController', function($scope) {
// we will store all of our form data in this object
$scope.formData = {};
// function to process the form
$scope.processForm = function() {
alert('awesome!');
};
});
现在,我们拥有了依赖注入 ngAnimate 和 ui.router 的 Angular 模块,也有已经创建好的路由。注意,在这里我们如何为每个状态定义 url ,视图文件( templateUrl )和控制器。 form
将会作为主状态,它可以通过 .
表示的子状态,例如 在 form.profile
中的 .
。这背后的想法是,每个嵌套状态将被纳入主表单视图( main form view ),作为应用程序改变的状态。我们会在下一个章节证明这一点。我们现在要为表单和它的每一个嵌套状态创建视图。
表单模板视图 ( form.html )
让我们开始创建 form.html 文件。它将会被作为剩下的表单视图文件的模板文件,就像 index.html 被用作整个工程的总模板一样。所有我们需要做的是将 ui-view 包含在这个文件中,使嵌套状态知道从哪里注入它们的视图。
<!-- form.html -->
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<div id="form-container">
<div class="page-header text-center">
<h2>Let's Be Friends</h2>
<!-- the links to our nested states using relative paths -->
<!-- add the active class if the state matches our ui-sref -->
<div id="status-buttons" class="text-center">
<a ui-sref-active="active" ui-sref=".profile"><span>1</span> Profile</a>
<a ui-sref-active="active" ui-sref=".interests"><span>2</span> Interests</a>
<a ui-sref-active="active" ui-sref=".payment"><span>3</span> Payment</a>
</div>
</div>
<!-- use ng-submit to catch the form submission and use our Angular function -->
<form id="signup-form" ng-submit="processForm()">
<!-- our nested state views will be injected here -->
<div id="form-views" ui-view></div>
</form>
</div>
<!-- show our formData as it is being typed -->
<pre>
{{ formData }}
</pre>
</div>
</div>
注意,这是我们第二次在工程中使用 ui-view 了,这也正是 UI Router 为何如此强大;允许嵌套状态和视图。这为我们创建应用提供了很大的灵活性。更多关于 UI Router 视图的信息,可以查阅它的官方文档。添加基于状态 Active 类,我们希望每一个状态按钮在它是活动的时候能够显示出来。为了做到这一点,我们使用 UI Router 提供的 ui-sref-active 的指令。当 ui-sref 匹配当前的状态时,这样就会添加我们指定的类。为你的表单添加校验,你可以阅读 AngularJS Form Validation 这时候,你可能想知道我们表单是看起来是什么样子,让我们进入浏览器来看一看!
到达这里,不是所有的事情都是我们希望的那样,但是已经有伟大的事情开始了。让我们继续推进,添加一些样式,然后再添加嵌套视图和动画。
基本的样式 (style.css)
为了得到一个好看的表单,我们设置 form-container 和 status-buttons 样式。
/* style.css */
/* BASIC STYLINGS
============================================================================= */
body { padding-top:20px; }
/* form styling */
#form-container { background:#2f2f2f; margin-bottom:20px;
border-radius:5px; }
#form-container .page-header { background:#151515; margin:0; padding:30px;
border-top-left-radius:5px; border-top-right-radius:5px; }
/* numbered buttons */
#status-buttons { }
#status-buttons a { color:#FFF; display:inline-block; font-size:12px; margin-right:10px; text-align:center; text-transform:uppercase; }
#status-buttons a:hover { text-decoration:none; }
/* we will style the span as the circled number */
#status-buttons span { background:#080808; display:block; height:30px; margin:0 auto 10px; padding-top:5px; width:30px;
border-radius:50%; }
/* active buttons turn light green-blue*/
#status-buttons a.active span { background:#00BC8C; }
现在,按钮看起来好看多了,让我们继续嵌套视图(nested views)。
嵌套表单视图 form-profile.html, form-interests.html, form-payment.html
这会是容易的部分。我们定义不同的带有输入框的视图。我们把它们和 formData 对象绑定,使我们可以看到表单中输入的数据。这里有我们的视图文件:
Form Profile View
<!-- form-profile.html -->
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" name="name" ng-model="formData.name">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control" name="email" ng-model="formData.email">
</div>
<div class="form-group row">
<div class="col-xs-6 col-xs-offset-3">
<a ui-sref="form.interests" class="btn btn-block btn-info">
Next Section <span class="glyphicon glyphicon-circle-arrow-right"></span>
</a>
</div>
</div>
Form Interests View
<!-- form-interests.html -->
<label>What's Your Console of Choice?</label>
<div class="form-group">
<div class="radio">
<label>
<input type="radio" ng-model="formData.type" value="xbox" checked>
I like XBOX
</label>
</div>
<div class="radio">
<label>
<input type="radio" ng-model="formData.type" value="ps">
I like PS4
</label>
</div>
</div>
<div class="form-group row">
<div class="col-xs-6 col-xs-offset-3">
<a ui-sref="form.payment" class="btn btn-block btn-info">
Next Section <span class="glyphicon glyphicon-circle-arrow-right"></span>
</a>
</div>
</div>
Form Payment View
<!-- form-payment.html -->
<div class="text-center">
<span class="glyphicon glyphicon-heart"></span>
<h3>Thanks For Your Money!</h3>
<button type="submit" class="btn btn-danger">Submit</button>
</div>
那么现在,我们拥有三个定义好的视图,当我们查看表单时,它们会被展示。我们也使用 next button 和 ui-sref 连接到每个新状态。
当使用 ui-sref 时,你想连接已经在路由中定义过的状态,而不是 URL。Angular 会使用 ui-sref 为你创建 href 。
为 form 添加动画
从一开始,ngAnimate 就已经进入到我们的工程,当我们改变状态,已经添加用于动画的类。它会自动添加类 ng-enter 和 ng-leave 用于 view 显示和消失。现在我们所要做的就是设置那些样式,我们有我们的完成表单!要理解 Angular 动画,这篇文章是一个很好的起点。让我们进入 CSS 文件,添加动画,并把它们应用到我们的表单。
/* style.css */
/* ANIMATION STYLINGS
============================================================================= */
#signup-form { position:relative; min-height:300px; overflow:hidden; padding:30px; }
#form-views { width:auto; }
/* basic styling for entering and leaving */
/* left and right added to ensure full width */
#form-views.ng-enter,
#form-views.ng-leave { position:absolute; left:30px; right:30px;
transition:0.5s all ease; -moz-transition:0.5s all ease; -webkit-transition:0.5s all ease;
}
/* enter animation */
#form-views.ng-enter {
-webkit-animation:slideInRight 0.5s both ease;
-moz-animation:slideInRight 0.5s both ease;
animation:slideInRight 0.5s both ease;
}
/* leave animation */
#form-views.ng-leave {
-webkit-animation:slideOutLeft 0.5s both ease;
-moz-animation:slideOutLeft 0.5s both ease;
animation:slideOutLeft 0.5s both ease;
}
/* ANIMATIONS
============================================================================= */
/* slide out to the left */
@keyframes slideOutLeft {
to { transform: translateX(-200%); }
}
@-moz-keyframes slideOutLeft {
to { -moz-transform: translateX(-200%); }
}
@-webkit-keyframes slideOutLeft {
to { -webkit-transform: translateX(-200%); }
}
/* slide in from the right */
@keyframes slideInRight {
from { transform:translateX(200%); }
to { transform: translateX(0); }
}
@-moz-keyframes slideInRight {
from { -moz-transform:translateX(200%); }
to { -moz-transform: translateX(0); }
}
@-webkit-keyframes slideInRight {
from { -webkit-transform:translateX(200%); }
to { -webkit-transform: translateX(0); }
}
首先,我们设置表单样式,当一个新的视图离开或进入的时候,它们是绝对定位的。这样可以确保当进入的时候,一个视图不会推挤其他视图。其次,我们在 .ng-enter 和 .ng-leave 类里应用动画。再次,我们使用 @Keyframes 定义动画。随着所有部分一起工作起来,我们全部表单都具有了 Angular 动画。UI Router based states, and Angular data-binding.
结论
UI-Router,ngAnimate,和所有在 Angular 中有趣的东西能走到一起去创造伟大的应用。希望这篇文章向您展示如何制作一个多步骤的表单,并使用多种 Angular 的技术和工具来构建它。这些概念已经被应用到许多其他的用户界面。感谢您的阅读,大胆的说出你建议和提出问题。
演示:http://embed.plnkr.co/M03tYgtfqNH09U4x5pHC/preview
代码:http://plnkr.co/edit/M03tYgtfqNH09U4x5pHC?p=preview