Angular項目構建指南 - 再也不爲angular構建而猶豫不決

    前言css

    接觸Angular也有小半個月了,雖然沒有使勁折騰,不過正所謂"no zuo no die".學一門新東西,很差好折騰一下總以爲對不起祖國,最不起人民...好像扯遠了,想寫前言來着.爲何要寫這篇構建指南?最大的緣由是爲了給正在找這方面資料,掙扎於各類說法中的同窗一個借鑑,同時我也把本身的經驗記錄下來,一箭雙鵰.
html

    正文
前端

    若是你不知道什麼是Angular或者根本沒據說過,那麼我接下來所說的對你來講毫無益處,不過若是你打算之後會接觸Angular或者乾脆要漲漲姿式~讀下去仍是有點用的.
html5

    Angular和它以前所出現的其他前端框架最大的不一樣,在於它的核心再也不是DOM,而是數據,是model.咱們慣用的不論是單純的jQuery仍是MVC的Backbone,它們本質還是讓咱們更方便更有條理的操做DOM,可是Angular不是.經過一系列魔術般的手法,它將一切的重心轉移到數據上.以開發應用而不是操做節點的方式去開發Web,一切以數據爲中心,數據的變化驅動了一切,包括行爲.
git

    文本主題,如何構建一個angular項目?
angularjs

    坦白說最開始構建一個項目的時候,雖然很小可是很糾結.我自己是有點完美主義的,因此雖然一開始什麼都沒有也想作到盡善盡美.由於聽過不少前輩的經驗,說若是框架基礎沒搭好,等到後來不論是重構仍是維護都是一場噩夢.因此一開始當心意義,但願能將項目儘可能搭建的結實而且益於維護和開發.
github

    在搭建伊始首先遇到的一個問題,就是到底要不要引入requirejs或者seajs這類依賴管理的工具?
ajax

    我自己沒有多少語言或者技術的上的情節,對於各個大神也沒有多少膜拜的憧憬(更多的是我根本不清楚誰是大神,也從沒去找過).因此對於我來說不論是requirejs的AMD仍是seajs的CMD,從實現的角度上來說都是作了同一個工做.在考慮一個Angular應用到底需不須要這種工具的時候,我也在網上看了不少人的說法.我總結一句就是,基本都和沒說同樣,也就是用不用隨便,看狀況.
gulp

    那麼我能有什麼好的答案,其實我如今的答案就是:"能夠不用".怎麼說是能夠不用呢,若是你不用requirejs也能知足項目的開發以及各類需求,那麼就別用了.angular自己的模塊已經作到了依賴注入,因此咱們不須要經過requirejs進行異步加載也能夠很好的用下去.
bootstrap

    固然,若是你開發過程當中發覺仍是有些地方須要,那麼也能夠加上去.本文裏我會詳細說明這兩種方式的構建方法.可是這裏個人觀點已經代表了:在不須要的狀況下,不要用.

    (1) 不用requirejs直接構建Angular

    之因此不使用requirejs就直接構建angular,由於angular對於依賴的管理以及angular的使用場景徹底能夠作到這一點.首先在以來上,angular的依賴注入是個好東西,不瞭解的同窗能夠去搜一下資料.我這裏簡單的說,就是當我須要一個module的時候,我不用管它在哪,它是什麼.我只要知道它的名字而後告訴angular就能夠了,至於怎麼將它的對象傳遞過來,怎麼找到的,angular本身會去處理.

angular.module('myApp', [
  'ngRoute',
]);

    例如這裏的ngRoute,我須要知道ngRoute怎麼來的,在哪裏.只要有一個模塊定義爲ngRoute我就能夠直接拿來用.

    鑑於Angular如此的給力,剩下的事情就好辦了.咱們只須要從功能和業務兩方面將文件劃分紅module就能夠了,而後將全部的庫文件在頁面上經過script標籤引用,再將全部的業務文件也便是咱們本身寫的js合併爲一個all.js加載到頁面上便可.

    這裏文件的劃分遵循angular官方的推薦方式:

|--js
   |--app.js                     // app啓動文件,用於app配置
   |--controllers.js          // controllers也就是存放咱們本身的業務文件
   |--directives.js            // 指令文件(指令可共用)
   |--fliters.js                  // 過濾器文件(過濾器可共用)
   |--services.js             //  服務文件(可共用,通常是與服務器交互的服務)
|--partials
   |--html1.html  
   |--html2.html
|--index.html

    app.js

'use strict';


// Declare app level module which depends on filters, and services
angular.module('myApp', [
  'ngRoute',
  'myApp.filters',
  'myApp.services',
  'myApp.directives',
  'myApp.controllers'
]).
config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/view1', {templateUrl: 'partials/partial1.html', controller: 'MyCtrl1'});
  $routeProvider.when('/view2', {templateUrl: 'partials/partial2.html', controller: 'MyCtrl2'});
  $routeProvider.otherwise({redirectTo: '/view1'});
}]);

    controllers.js

'use strict';

/* Controllers */

angular.module('myApp.controllers', [])
  .controller('MyCtrl1', ['$scope', function($scope) {

  }])
  .controller('MyCtrl2', ['$scope', function($scope) {

  }]);

    directives.js

'use strict';

/* Directives */


angular.module('myApp.directives', []).
  directive('appVersion', ['version', function(version) {
    return function(scope, elm, attrs) {
      elm.text(version);
    };
  }]);

    filters.js

'use strict';

/* Filters */

angular.module('myApp.filters', []).
  filter('interpolate', ['version', function(version) {
    return function(text) {
      return String(text).replace(/\%VERSION\%/mg, version);
    };
  }]);

    services.js

'use strict';

/* Services */


// Demonstrate how to register services
// In this case it is a simple value service.
angular.module('myApp.services', []).
  value('version', '0.1');

    index.html

<!DOCTYPE html>
<!--[if lt IE 7]>      <html ng-app="myApp" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html ng-app="myApp" class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html ng-app="myApp" class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html ng-app="myApp"> <!--<![endif]-->
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>My AngularJS App</title>
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="bower_components/html5-boilerplate/css/normalize.css">
  <link rel="stylesheet" href="bower_components/html5-boilerplate/css/main.css">
  <link rel="stylesheet" href="css/app.css"/>
  <script src="bower_components/html5-boilerplate/js/vendor/modernizr-2.6.2.min.js"></script>
</head>
<body>
  <ul>
    <li><a href="#/view1">view1</a></li>
    <li><a href="#/view2">view2</a></li>
  </ul>

  <!--[if lt IE 7]>
      <p>You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
  <![endif]-->

  <div ng-view></div>

  <div>Angular seed app: v<span app-version></span></div>

  <!-- In production use:
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/x.x.x/angular.min.js"></script>
  -->
  <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/services.js"></script>
  <script src="js/controllers.js"></script>
  <script src="js/filters.js"></script>
  <script src="js/directives.js"></script>
</body>
</html>

    如此在不使用requirejs的情景下,項目就構建完成了.還有幾個補充點就是其一你能夠將controllers繼續拆分爲多個controller模塊,這裏能夠徹底按照你的業務進行劃分.好比user目錄下userController等等.而後將全部這些咱們本身寫的文件經過grunt或者gulp進行合併爲一個單獨的總的文件all.js這樣在頁面中除了庫文件只要這一個文件就好了.angular的module所帶來的好處就是這樣合併的文件,不用在意js合併的順序,由於它是經過angular依賴注入的.

    (2) 經過requirejs構建

    這種方式的構建可能對於某些人來說更加清晰,結構和上面的基本同樣,多了一個man.js用來配置requirejs,單獨拆分出routes.js以及一個controller文件夾經過requirejs將controller一個個拆分出來,按需的異步加載.

    index.html

<!doctype html>
<html ng-app>
<head>
<title>Angular-RequireJS sample app</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" media="all" href="app/css/app.css" />
</head>
<body >
<h1>AngularJS + RequireJS</h1>
<ul>
<li><a href="#/view1">View 1</a></li>
<li><a href="#/view2">View 2</a></li>
</ul>
<div ng-view></div>
<script data-main="app/js/main" src="/bower_components/requirejs/require.js"></script>
</body>
</html>

    main.js

require.config({
	paths: {
		angular: '../../bower_components/angular/angular',
		angularRoute: '../../bower_components/angular-route/angular-route',
		angularMocks: '../../bower_components/angular-mocks/angular-mocks',
		text: '../../bower_components/requirejs-text/text'
	},
	shim: {
		'angular' : {'exports' : 'angular'},
		'angularRoute': ['angular'],
		'angularMocks': {
			deps:['angular'],
			'exports':'angular.mock'
		}
	},
	priority: [
		"angular"
	]
});

//http://code.angularjs.org/1.2.1/docs/guide/bootstrap#overview_deferred-bootstrap
window.name = "NG_DEFER_BOOTSTRAP!";

require( [
	'angular',
	'app',
	'routes'
], function(angular, app, routes) {
	'use strict';
	var $html = angular.element(document.getElementsByTagName('html')[0]);

	angular.element().ready(function() {
		angular.resumeBootstrap([app['name']]);
	});
});

    app.js

define([
	'angular',
	'filters',
	'services',
	'directives',
	'controllers',
	'angularRoute',
	], function (angular, filters, services, directives, controllers) {
		'use strict';

		// Declare app level module which depends on filters, and services
		
		return angular.module('myApp', [
			'ngRoute',
			'myApp.controllers',
			'myApp.filters',
			'myApp.services',
			'myApp.directives'
		]);
});

    controllers.js

define(['angular', 'services'], function (angular) {
	'use strict';

	/* Controllers */
	
	return angular.module('myApp.controllers', ['myApp.services'])
		// Sample controller where service is being used
		.controller('MyCtrl1', ['$scope', 'version', function ($scope, version) {
			$scope.scopedAppVersion = version;
		}])
		// More involved example where controller is required from an external file
		.controller('MyCtrl2', ['$scope', '$injector', function($scope, $injector) {
			require(['controllers/myctrl2'], function(myctrl2) {
				// injector method takes an array of modules as the first argument
				// if you want your controller to be able to use components from
				// any of your other modules, make sure you include it together with 'ng'
				// Furthermore we need to pass on the $scope as it's unique to this controller
				$injector.invoke(myctrl2, this, {'$scope': $scope});
			});
		}]);
});

    directives.js

define(['angular', 'services'], function(angular, services) {
	'use strict';

  /* Directives */

	angular.module('myApp.directives', ['myApp.services'])
		.directive('appVersion', ['version', function(version) {
			return function(scope, elm, attrs) {
				elm.text(version);
		};
	}]);
});

    filters.js

define(['angular', 'services'], function (angular, services) {
	'use strict';

	/* Filters */
  
	angular.module('myApp.filters', ['myApp.services'])
		.filter('interpolate', ['version', function(version) {
			return function(text) {
				return String(text).replace(/\%VERSION\%/mg, version);
			};
	}]);
});

    routes.js

define(['angular', 'app'], function(angular, app) {
	'use strict';

	return app.config(['$routeProvider', function($routeProvider) {
		$routeProvider.when('/view1', {
			templateUrl: 'app/partials/partial1.html',
			controller: 'MyCtrl1'
		});
		$routeProvider.when('/view2', {
			templateUrl: 'app/partials/partial2.html',
			controller: 'MyCtrl2'
		});
		$routeProvider.otherwise({redirectTo: '/view1'});
	}]);

});

    services.js

define(['angular'], function (angular) {
	'use strict';
	
  /* Services */

  // Demonstrate how to register services
  // In this case it is a simple value service.
	angular.module('myApp.services', [])
		.value('version', '0.1');
});

    controllers文件夾中一個單獨controlle文件,myCtrl2.js

define([], function() {
	return ['$scope', '$http', function($scope, $http) {
		// You can access the scope of the controller from here
		$scope.welcomeMessage = 'hey this is myctrl2.js!';

		// because this has happened asynchroneusly we've missed
		// Angular's initial call to $apply after the controller has been loaded
		// hence we need to explicityly call it at the end of our Controller constructor
		$scope.$apply();
	}];
});

    結尾

    寫到這應該差很少了,就快超字數了.一般狀況下Angular應用的構建這樣就能夠了,由於比起傳統框架angular的代碼量上確定會有優點,因此一些沒必要要的東西就不用引入了.上面這些也是我在這段時間的項目中遇到而且作過的,已經實戰過了,因此若是有相似需求的同窗能夠沒必要在此填坑.

    最後留個彩蛋吧,在不用requirejs的狀況下,angular也是能夠實現異步加載的,只要經過一個很是小巧的庫就能夠,名字叫script.js.https://github.com/ded/script.js

相關文章
相關標籤/搜索