1.切换分支到step7,并启动项目
git checkout step-7
npm start
2.需求:
在步骤7之前,应用只给我们的用户提供了一个简单的界面(一张所有手机的列表),并且所有的模板代码位于index.html
文件中。下一步是增加一个能够显示我们列表中每一部手机详细信息的页面。可以先看一下step6和7的代码区别 .
为了增加详细信息视图,我们可以拓展index.html
来同时包含两个视图的模板代码,但是这样会很快给我们带来巨大的麻烦。相反,我们要把index.html
模板转变成“布局模板”。这是我们应用所有视图的通用模板。其他的“局部布局模板”随后根据当前的“路由”被充填入,从而形成一个完整视图展示给用户。
AngularJS中应用的路由通过$routeProvider来声明,它是$route服务的提供者。这项服务使得控制器、视图模板与当前浏览器的URL可以轻易集成。应用这个特性我们就可以实现深链接,它允许我们使用浏览器的历史(回退或者前进导航)和书签。
3.效果:
可以很明显的注意到当访问
http://localhost:8000/app时,其URL被重定向到了http://localhost:8000/app/#/phones页面.
4.实现代码
app/index.html
<!doctype html>
<html lang="en" ng-app="phonecatApp">
<head>
<meta charset="utf-8">
<title>Google Phone Gallery</title>
<link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap.css">
<link rel="stylesheet" href="css/app.css">
<script src="../bower_components/angular/angular.js"></script>
<script src="../bower_components/angular-route/angular-route.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
</head>
<body><div ng-view></div>
</body>
</html>
可以发现其实现代码非常简单,只有一个div标签,
然后一个ng-view指令.同时要注意的是引入了angular.js、angular-route.js、app.js和controllers.js,这里将按照顺序贴出其js代码.并加以说明.
app/app.js
‘use strict‘;/* App Module */
var phonecatApp = angular.module(‘phonecatApp‘, [
‘ngRoute‘,
‘phonecatControllers‘
]);phonecatApp.config([‘$routeProvider‘,
function($routeProvider) {
$routeProvider.
when(‘/phones‘, {
templateUrl: ‘partials/phone-list.html‘,
controller: ‘PhoneListCtrl‘
}).
when(‘/phones/:phoneId‘, {
templateUrl: ‘partials/phone-detail.html‘,
controller: ‘PhoneDetailCtrl‘
}).
otherwise({
redirectTo: ‘/phones‘
});
}]);
app/controllers.js
‘use strict‘;/* Controllers */
var phonecatControllers = angular.module(‘phonecatControllers‘, []);
phonecatControllers.controller(‘PhoneListCtrl‘, [‘$scope‘, ‘$http‘,
function($scope, $http) {
$http.get(‘phones/phones.json‘).success(function(data) {
$scope.phones = data;
});$scope.orderProp = ‘age‘;
}]);phonecatControllers.controller(‘PhoneDetailCtrl‘, [‘$scope‘, ‘$routeParams‘,
function($scope, $routeParams) {
$scope.phoneId = $routeParams.phoneId;
}]);
app/partials/phone-detail.html
:
TBD: detail view for {{phoneId}}
代码说明:
1).index.html中<html lang="en"
ng-app="phonecatApp">定义了要使用的ng-app是"phoneApp",然后定义了:<div
ng-view></div>,这里可以ngView:查看一下ng-view的api说明,ngView ,ngView是一个指令,主要用于通过已经渲染的模板将当前的$route服务与主页面(index.html)联结起来.
ngView
is a directive that complements the $route service by including the rendered template of the current route into the main layou
(index.html
) file. Every time the current route changes, the included view changes with it according to the configuration of the$route
service.
用法:
- as element: (This directive can be used as custom element, but be aware
of IE restrictions).<ng-view
[onload=""]
[autoscroll=""]>
...
</ng-view> - as attribute:
<ANY
[onload=""]
[autoscroll=""]>
...
</ANY> - as CSS class:
<ANYclass="[onload: ;] [autoscroll: ;]"> ... </ANY>
在本例中用到的是as CSS class,这里ngview是要和$route成队使用的.
2).关于app.js
为了给我们的应用配置路由,我们需要给应用创建一个模块。我们管这个模块叫做phonecat
,并且通过使用config
API,我们请求把$routeProvider
注入到我们的配置函数并且使用$routeProvider.when
API来定义我们的路由规则。
注意到在注入器配置阶段,提供者也可以同时被注入,但是一旦注入器被创建并且开始创建服务实例的时候,他们就不再会被外界所获取到。
我们的路由规则定义如下
- 当URL
映射段为/phones
时,手机列表视图会被显示出来。为了构造这个视图,AngularJS会使用phone-list.html
模板和PhoneListCtrl
控制器。 - 当URL
映射段为/phone/:phoneId
时,手机详细信息视图被显示出来。这里:phoneId
是URL的变量部分。为了构造手机详细视图,AngularJS会使用phone-detail.html
模板和PhoneDetailCtrl
控制器。我们重用之前创造过的PhoneListCtrl
控制器,同时我们为手机详细视图添加一个新的PhoneDetailCtrl
控制器,把它存放在app/js/controllers.js
文件里。 $route.otherwise({redirectTo:
语句使得当浏览器地址不能匹配我们任何一个路由规则时,触发重定向到
‘/phones‘})/phones
。
注意到在第二条路由声明中:phoneId
参数的使用。$route
服务使用路由声明/phones/:phoneId
作为一个匹配当前URL的模板。所有以:
符号声明的变量(此处变量为phones
)都会被提取,然后存放在$routeParams对象中。
3).app/js/controllers.js
这里用的是$http
get方法将phones/phones.json的值读取出来;
定义phonecatControllers,并配置phonecatControllers,将$routeParams作为变量,将值再赋给$scope.phoneId
,然后显示的routeParams.phoneId;
4) phone-detail.html
phone-detail.html中将控制器里phoneId的值显示出来.
5.测试
执行如下命令开始测试:
[email protected]:~/develop/angular-phonecat$ npm run protractor
angular-phonecat/test/e2e/scenarios.js
‘use strict‘;/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */
describe(‘PhoneCat App‘, function() {
it(‘should redirect index.html to index.html#/phones‘, function() {
browser.get(‘app/index.html‘);
browser.getLocationAbsUrl().then(function(url) {
expect(url.split(‘#‘)[1]).toBe(‘/phones‘);
});
});describe(‘Phone list view‘, function() {
beforeEach(function() {
browser.get(‘app/index.html#/phones‘);
});it(‘should filter the phone list as user types into the search box‘, function() {
var phoneList = element.all(by.repeater(‘phone in phones‘));
var query = element(by.model(‘query‘));expect(phoneList.count()).toBe(20);
query.sendKeys(‘nexus‘);
expect(phoneList.count()).toBe(1);query.clear();
query.sendKeys(‘motorola‘);
expect(phoneList.count()).toBe(8);
});it(‘should be possible to control phone order via the drop down select box‘, function() {
var phoneNameColumn = element.all(by.repeater(‘phone in phones‘).column(‘{{phone.name}}‘));
var query = element(by.model(‘query‘));function getNames() {
return phoneNameColumn.map(function(elm) {
return elm.getText();
});
}query.sendKeys(‘tablet‘); //let‘s narrow the dataset to make the test assertions shorter
expect(getNames()).toEqual([
"Motorola XOOM\u2122 with Wi-Fi",
"MOTOROLA XOOM\u2122"
]);element(by.model(‘orderProp‘)).findElement(by.css(‘option[value="name"]‘)).click();
expect(getNames()).toEqual([
"MOTOROLA XOOM\u2122",
"Motorola XOOM\u2122 with Wi-Fi"
]);
});it(‘should render phone specific links‘, function() {
var query = element(by.model(‘query‘));
query.sendKeys(‘nexus‘);
element(by.css(‘.phones li a‘)).click();
browser.getLocationAbsUrl().then(function(url) {
expect(url.split(‘#‘)[1]).toBe(‘/phones/nexus-s‘);
});
});
});describe(‘Phone detail view‘, function() {
beforeEach(function() {
browser.get(‘app/index.html#/phones/nexus-s‘);
});it(‘should display placeholder page with phoneId‘, function() {
expect(element(by.binding(‘phoneId‘)).getText()).toBe(‘nexus-s‘);
});
});
});
测试结果:
Using ChromeDriver directly...
.....Finished in 7.368 seconds
5 tests, 8 assertions, 0 failures
AngularJS学习---Routing(路由) & Multiple Views(多个视图) step
7