步骤10——行为处理

在这一步中,我们会对手机图片添加点击支持,点击后会在手机详细说明页面显示新的图形。

  • 手机详细说明显示当前手机的一个巨大的图片和一些缩略图。我们点击缩略图会显示对应的大图片,这个效果很令人兴奋。让我们看看如何利用Angular来实现。

工作区切换到步骤10

直接用浏览器访问步骤10在线演示

大多数的重要改变都会列在下面,不过你也可以在GitHub看到完整的差异。

控制器

app/js/controllers.js:

  1. ...
  2. var phonecatControllers = angular.module('phonecatControllers',[]);
  3. phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$http',
  4. function($scope, $routeParams, $http) {
  5. $http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
  6. $scope.phone = data;
  7. $scope.mainImageUrl = data.images[0];
  8. });
  9. $scope.setImage = function(imageUrl) {
  10. $scope.mainImageUrl = imageUrl;
  11. }
  12. }]);

PhoneDetailCtrl控制器中,我们创建了一个mainImageUrl模型属性,并且设置默认值为第一个手机图片的URL。

我们也创建可一个setImage的行为处理函数,来改变mainImageUrl

模板

app/partials/phone-detail.html:

  1. <img ng-src="{{mainImageUrl}}" class="phone">
  2. ...
  3. <ul class="phone-thumbs">
  4. <li ng-repeat="img in phone.images">
  5. <img ng-src="{{img}}" ng-click="setImage(img)">
  6. </li>
  7. </ul>
  8. ...

我们把ngSrc指令通过mainImageUrl绑定到大图片的URL。

我们也为缩略图注册了ngClick处理,当用户点击任何缩略图的时候进行处理,这个处理会使用setImage行为处理函数依据点击的缩略图来改变mainImageUrl的值,从而改变大图显示内容。

测试

为了检测新特性,我们需要写2个端到端测试。其中一个验证手机详细说明页面开始时,主要图(大图)是否是对应显示的第1个手机图片(默认值)。第二个测试检查点击一些缩略图是否会正确进行图片切换。 test/e2e/secnarios.js:

  1. ...
  2. describe('Phone detail view', function() {
  3. ...
  4. it('should display the first phone image as the main phone image', function() {
  5. expect(element(by.css('img.phone')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/);
  6. });
  7. it('should swap main image if a thumbnail image is clicked on', function() {
  8. element(by.css('.phone-thumbs li:nth-child(3) img')).click();
  9. expect(element(by.css('img.phone')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/);
  10. element(by.css('.phone-thumbs li:nth-child(1) img')).click();
  11. expect(element(by.css('img.phone')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/);
  12. });
  13. });

我们现在可以运行npm run protractor来完成测试了。

你也可以重构单元测试,因为这一步添加了mainImageUrl模型到PhoneDetailCtrl控制器中。下面,我们创建一个叫xyzPhoneData的函数,它会返回images属性的json数据来完成测试。 test/unit/controllersSpec.js:

  1. ...
  2. beforeEach(module('phonecatApp'));
  3. ...
  4. describe('PhoneDetailCtrl', function(){
  5. var scope, $httpBackend, ctrl,
  6. xyzPhoneData = function() {
  7. return {
  8. name: 'phone xyz',
  9. images: ['image/url1.png', 'image/url2.png']
  10. }
  11. };
  12. beforeEach(inject(function(_$httpBackend_, $rootScope, $routeParams, $controller) {
  13. $httpBackend = _$httpBackend_;
  14. $httpBackend.expectGET('phones/xyz.json').respond(xyzPhoneData());
  15. $routeParams.phoneId = 'xyz';
  16. scope = $rootScope.$new();
  17. ctrl = $controller('PhoneDetailCtrl', {$scope: scope});
  18. }));
  19. it('should fetch phone detail', function() {
  20. expect(scope.phone).toBeUndefined();
  21. $httpBackend.flush();
  22. expect(scope.phone).toEqual(xyzPhoneData());
  23. });
  24. });

现在单元测试能通过了。

尝试

让我们给PhoneDetailCtrl添加新的方法:

  1. $scope.hello = function(name) {
  2. alert('Hello ' + (name || 'world') + '!');
  3. }

并把

  1. <button ng-click="hello('Elmo')">Hello</button>
  1. 添加到`phone-detail.html`模板中。

小结

我们的手机图片已经可以在指定位置进行切换了,我们准备进入步骤11来学习一个更好的获取数据的方法。