AngularJS PhoneCat代碼分析

原文:http://www.tuicool.com/articles/ym6Jfenjavascript

 

AngularJS 官方網站提供了一個用於學習的示例項目:PhoneCat。這是一個Web應用,用戶能夠瀏覽一些Android手機,瞭解它們的詳細信息,並進行搜索和排序操做。php

本文主要分析 AngularJS 官方網站提供的一個用於學習的示例項目 PhoneCat 的構建、測試過程以及代碼的運行原理。但願可以對 PhoneCat 項目有一個更加深刻全面的認識。這其中包括如下內容:css

  • 該項目如何運行起來的
  • 該項目如何進行前端單元測試
  • AngularJS 相關代碼分析

如下內容若有理解不正確,歡迎指正!

環境搭建

對於 PhoneCat 項目的開發環境和測試環境的搭建,官方網站上提供了詳細的指導: http://docs.angularjs.org/tutorial ,你能夠找到一些中文的翻譯。html

PhoneCat 項目的源代碼託管在 GitHub 上,能夠經過下面命令下載源代碼:前端

$ git clone --depth=20 https://github.com/angular/angular-phonecat.git 

--depth=20 選項的意思爲:僅下載最近20次的代碼提交版本;這麼作能夠減小下載的文件大小,加快下載。java

 

PhoneCat 是一個 Web 應用程序,所以最好在 Web 服務器中運行,以期得到最佳結果。官方推薦安裝 Node.js 。node

 

PhoneCat 項目的運行與測試依賴一些別的工具,能夠在安裝 Node.js 後經過 npm 命令來安裝這些依賴包。如下命令需在 angular-phonecat 項目路徑下運行:jquery

$ npm install 

運行該命令後,會在 angular-phonecat 項目路徑下安裝如下依賴包:git

  • Bower 包管理器
  • Http-Server 輕量級Web服務器
  • Karma 用於運行單元測試
  • Protractor 用於運行端到端測試

幾乎全部的 AngularJS 學習教程,都會寫到用這個命令來啓動服務:angularjs

$ node scripts/web-server.js 

但實際上 PhoneCat 項目已經放棄使用 web-server 了,git 上取下來的的項目裏沒有 scripts/web-server.js 文件了。

咱們能夠用下面的方式來啓動工程:

$ npm start 

而後經過 http://localhost:8000/app/index.html 訪問。

依賴包介紹

在克隆項目以後,目錄以下:

➜  angular-phonecat git:(master) ✗ tree -L 2 . ├── LICENSE ├── README.md ├── app │ ├── bower_components │ ├── css │ ├── img │ ├── index.html │ ├── js │ ├── partials │ └── phones ├── bower.json ├── package.json ├── scripts │ ├── private │ └── update-repo.sh └── test  ├── e2e  ├── karma.conf.js  ├── protractor-conf.js  └── unit 20 directories, 8 files 

這個目錄下存在一個文件 package.json,該文件是作什麼用的呢?

 

在 NodeJS 項目中,用 package.json 文件來聲明項目中使用的模塊,這樣在新的環境部署時,只要在 package.json 文件所在的目錄執行 npm install 命令便可安裝所須要的模塊。

 

關於 package.json 中可配置的選項請參考 package.json字段全解 。

從該文件能夠看出 PhoneCat 的依賴:

"devDependencies": {  "karma": "^0.12.16",  "karma-chrome-launcher": "^0.1.4",  "karma-jasmine": "^0.1.5",  "protractor": "~1.0.0",  "http-server": "^0.6.1",  "tmp": "0.0.23",  "bower": "^1.3.1",  "shelljs": "^0.2.6" } 

以及一些腳本:

"scripts": {  "postinstall": "bower install",  "prestart": "npm install",  "start": "http-server -a 0.0.0.0 -p 8000",  "pretest": "npm install",  "test": "node node_modules/karma/bin/karma start test/karma.conf.js",  "test-single-run": "node node_modules/karma/bin/karma start test/karma.conf.js --single-run",  "preupdate-webdriver": "npm install",  "update-webdriver": "webdriver-manager update",  "preprotractor": "npm run update-webdriver",  "protractor": "protractor test/protractor-conf.js",  "update-index-async": "node -e \"require('shelljs/global'); sed('-i', /\\/\\/@@NG_LOADER_START@@[\\s\\S]*\\/\\/@@NG_LOADER_END@@/, '//@@NG_LOADER_START@@\\n' + cat('bower_components/angular-loader/angular-loader.min.js') + '\\n//@@NG_LOADER_END@@', 'app/index-async.html');\"" } 

從上能夠看出運行 npm start 以前會運行 npm install ,而後運行 http-server -a 0.0.0.0 -p 8000 啓動一個 web 服務器,最後是運行 bower install安裝 bower 管理的包。

bower 管理的包由 bower.json 文件定義:

{ "name": "angular-phonecat", "description": "A starter project for AngularJS", "version": "0.0.0", "homepage": "https://github.com/angular/angular-phonecat", "license": "MIT", "private": true, "dependencies": { "angular": "1.3.x", "angular-mocks": "1.3.x", "jquery": "~2.1.1", "bootstrap": "~3.1.1", "angular-route": "1.3.x", "angular-resource": "1.3.x", "angular-animate": "1.3.x" } }

固然,package.json 文件中還定義了一些測試相關的命令。

bower

關於 bower 的介紹,參考博客內文章:bower介紹。

在本項目中,bower 下載的包保存在 angular-phonecat/app/bower_components 目錄下,依賴以下:

├── bower_components
│   ├── angular
│   ├── angular-animate
│   ├── angular-mocks
│   ├── angular-resource
│   ├── angular-route
│   ├── bootstrap
│   └── jquery

karma

Karma 是一個 Javascript 測試運行工具,能夠幫助你關閉反饋循環。Karma 能夠在特定的文件被修改時運行測試,它也能夠在不一樣的瀏覽器上並行測試。不一樣的設備能夠指向 Karma 服務器來覆蓋實際場景。

關於 Karma 的使用,本文不作介紹。

http-server

http-server 是一個簡單的零配置命令行 HTTP 服務器,基於 Node.js 。

在命令行中使用方式是:

$ node http-server 

在package.json 中定義方式是:

"scripts": { "start": "http-server -a 0.0.0.0 -p 8000", } 

支持的參數:

-p 端口號 (默認 8080) -a IP 地址 (默認 0.0.0.0) -d 顯示目錄列表 (默認 'True') -i 顯示 autoIndex (默認 'True') -e or --ext 若是沒有提供默認的文件擴展名(默認 'html') -s or --silent 禁止日誌信息輸出 --cors 啓用 CORS -o 在開始服務後打開瀏覽器 -h or --help 打印列表並退出 -c 爲 cache-control max-age header 設置Cache time(秒) ,禁用 caching, 則值設爲 -1 . 

Protractor

Protractor 是一個端對端的測試運行工具,模擬用戶交互,幫助你驗證你的 Angular 應用的運行情況。

Protractor 使用 Jasmine 測試框架來定義測試。Protractor 爲不一樣的頁面交互提供一套健壯的 API。

固然,也有其餘的端對端工具,不過 Protractor 有着本身的優點,它知道怎麼和 AngularJS 的代碼一塊兒運行,特別是面臨 $digest 循環的時候。

關於 Protractor 的使用,本文不作介紹。

ShellJS

ShellJS 是 Node.js 擴展,用於實現 Unix shell 命令執行,支持 Windows。

一個示例代碼:

require('shelljs/global'); if (!which('git')) { echo('Sorry, this script requires git'); exit(1); } // Copy files to release dir mkdir('-p', 'out/Release'); cp('-R', 'stuff/*', 'out/Release'); // Replace macros in each .js file cd('lib'); ls('*.js').forEach(function(file) { sed('-i', 'BUILD_VERSION', 'v0.1.2', file); sed('-i', /.*REMOVE_THIS_LINE.*\n/, '', file); sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, cat('macro.js'), file); }); cd('..'); // Run external tool synchronously if (exec('git commit -am "Auto-commit"').code !== 0) { echo('Error: Git commit failed'); exit(1); } 

在 PhoneCat 中,主要是用在下面:

"update-index-async": "node -e \"require('shelljs/global'); sed('-i', /\\/\\/@@NG_LOADER_START@@[\\s\\S]*\\/\\/@@NG_LOADER_END@@/, '//@@NG_LOADER_START@@\\n' + cat('bower_components/angular-loader/angular-loader.min.js') + '\\n//@@NG_LOADER_END@@', 'app/index-async.html');\"" 

測試

運行單元測試

PhoneCat 項目中的單元測試是使用 Karma 來完成的,全部的單元測試用例都存放在 test/unit 目錄下。能夠經過執行如下命令來運行單元測試:

$ npm test 

 

值得一提的是,在運行單元測試前,計算機上必須安裝 Google Chrome 瀏覽器,由於這裏用到了 karma-chrome-launcher 。

 

運行端到端測試

PhoneCat 項目使用端到端測試來保證 Web 應用的可操做性,而這個端到端測試是經過使用 Protractor 來實現的,全部的端到端測試用例都存放在test/e2e 目錄下。能夠經過執行如下步驟來運行端到端測試:

//更新webdriver,此命令只需運行一次
$ npm run update-webdriver //運行PhoneCat $ npm start 

打開另外一個命令行窗口,在其中運行:

$ npm run protractor 

代碼分析

在介紹了 PhoneCat 的運行和測試環境後,來看看 PhoneCat 的頁面和 js 是怎麼組織起來的。

  • 首先,從 index.html 內容能夠看到 PhoneCat 頁面使用 bootstrap 框架,而且引入了 jquery 以及 angular 的相關依賴,包括一些附加模塊: 路由 、 動畫 、 資源
  • angular 應用範圍由 ng-app 定義在 html 節點上,即做用於整個頁面,其名稱爲phonecatApp 。
  • 經過 ng-view 指定加載子視圖的位置,這裏主要包括 partials/phone-list.html 和 partials/phone-detail.html 兩個視圖。
  • app.js 是應用的入口,而且依賴 animations.js、controllers.js、filters.js、services.js 等文件。從這裏能夠看出,一個 angular 應用的 js 大概包括哪幾個部分的內容。

app.js 內容以下:

//JavaScript語法支持嚴格模式:若是在語法檢測時發現語法問題,則整個代碼塊失效,並致使一個語法異常;若是在運行期出現了違反嚴格模式的代碼,則拋出執行異常。 'use strict'; /* App Module */ //定義一個模塊,模塊名稱和頁面 ng-app 中內容一致 var phonecatApp = angular.module('phonecatApp', [ 'ngRoute', 'phonecatAnimations', 'phonecatControllers', 'phonecatFilters', 'phonecatServices' ]); //定義路由 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' }); }]); 

phonecatApp 模塊依賴其餘幾個模塊:ngRoute、phonecatAnimations、phonecatControllers、phonecatFilters、phonecatServices。

ngRoute 是內置的路由模塊,定義路由規則:

  • 當訪問 /phones ,由 PhoneListCtrl 控制器處理,而且由 partials/phone-list.html 模板渲染顯示內容。
  • 當訪問 /phones/:phoneId ,由 PhoneDetailCtrl 控制器處理,而且由partials/phone-detail.html 模板渲染顯示內容。
  • 若是不知足上面條件,則重定向到 /phones

phonecatAnimations 模塊是定義動畫效果,沒有真個模塊不影響程序的主要功能的運行,故不分析這部分代碼。

phonecatControllers 模塊定義在 controllers.js 文件中:

'use strict'; /* Controllers */ var phonecatControllers = angular.module('phonecatControllers', []); // 定義 PhoneListCtrl,並注入 Phone 對象 phonecatControllers.controller('PhoneListCtrl', ['$scope', 'Phone', function($scope, Phone) { $scope.phones = Phone.query(); $scope.orderProp = 'age'; }]); // 定義 PhoneDetailCtrl,並注入 Phone 對象和 $routeParams,$routeParams 封裝了路由參數。 phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams', 'Phone', function($scope, $routeParams, Phone) { $scope.phone = Phone.get({phoneId: $routeParams.phoneId}, function(phone) { //回調方法 $scope.mainImageUrl = phone.images[0]; }); $scope.setImage = function(imageUrl) { $scope.mainImageUrl = imageUrl; } }]); 

phonecatFilters 模塊定義在 filter.js 文件中,主要是自定義了一個過濾器checkmark :根據輸入是否有內容判斷返回  仍是  。

phonecatServices 模塊定義在 services.js 文件中:

'use strict'; /* Services */ var phonecatServices = angular.module('phonecatServices', ['ngResource']); // 定義 Phone 服務,並提供了一個 query 方法,還包括一個內置的 get 方法。調用 get 方法實際上就是調用 query 方法,而且能夠傳遞一個參數 phoneId phonecatServices.factory('Phone', ['$resource', function($resource){ return $resource('phones/:phoneId.json', {}, { query: {method:'GET', params:{phoneId:'phones'}, isArray:true} }); }]);
相關文章
相關標籤/搜索