Angular项目构建指南 - 不再为angular构建而犹豫不决(转)
阅读原文时间:2023年07月10日阅读:2

如果你不知道什么是Angular或者根本没听说过,那么我接下来所说的对你来说毫无益处,不过如果你打算以后会接触Angular或者干脆要涨涨姿势~读下去还是有点用的.

Angular和它之前所出现的其余前端框架最大的不同,在于它的核心不再是DOM,而是数据,是model.我们惯用的不管是单纯的jQuery还是MVC的Backbone,它们本质仍是让我们更方便更有条理的操作DOM,但是Angular不是.通过一系列魔术般的手法,它将一切的重心转移到数据上.以开发应用而不是操作节点的方式去开发Web,一切以数据为中心,数据的变化驱动了一切,包括行为.

文本主题,如何构建一个angular项目?

坦白说最开始构建一个项目的时候,虽然很小但是很纠结.我本身是有点完美主义的,所以虽然一开始什么都没有也想做到尽善尽美.因为听过很多前辈的经验,说如果框架基础没搭好,等到后来不管是重构还是维护都是一场噩梦.所以一开始小心意义,希望能将项目尽量搭建的结实并且益于维护和开发.

在搭建伊始首先遇到的一个问题,就是到底要不要引入requirejs或者seajs这类依赖管理的工具?

我本身没有多少语言或者技术的上的情节,对于各个大神也没有多少膜拜的憧憬(更多的是我根本不清楚谁是大神,也从没去找过).所以对于我来讲不管是requirejs的AMD还是seajs的CMD,从实现的角度上来讲都是做了同一个工作.在考虑一个Angular应用到底需不需要这种工具的时候,我也在网上看了很多人的说法.我总结一句就是,基本都和没说一样,也就是用不用随便,看情况.

那么我能有什么好的答案,其实我现在的答案就是:"可以不用".怎么说是可以不用呢,如果你不用requirejs也能满足项目的开发以及各种需求,那么就别用了.angular本身的模块已经做到了依赖注入,所以我们不需要通过requirejs进行异步加载也可以很好的用下去.

当然,如果你开发过程中发觉还是有些地方需要,那么也可以加上去.本文里我会详细说明这两种方式的构建方法.但是这里我的观点已经表明了:在不需要的情况下,不要用.

(1) 不用requirejs直接构建Angular

之所以不使用requirejs就直接构建angular,因为angular对于依赖的管理以及angular的使用场景完全可以做到这一点.首先在以来上,angular的依赖注入是个好东西,不了解的同学可以去搜一下资料.我这里简单的说,就是当我需要一个module的时候,我不用管它在哪,它是什么.我只要知道它的名字然后告诉angular就可以了,至于怎么将它的对象传递过来,怎么找到的,angular自己会去处理.

?

1

2

3

angular.module(``'myApp'``, [

'ngRoute'``,

]);

例如这里的ngRoute,我需要知道ngRoute怎么来的,在哪里.只要有一个模块定义为ngRoute我就可以直接拿来用.

鉴于Angular如此的给力,剩下的事情就好办了.我们只需要从功能和业务两方面将文件划分成module就可以了,然后将所有的库文件在页面上通过script标签引用,再将所有的业务文件也即是我们自己写的js合并为一个all.js加载到页面上即可.

这里文件的划分遵循angular官方的推荐方式:

?

1

2

3

4

5

6

7

8

9

10

|--js

|--app.js // app启动文件,用于app配置

|--controllers.js // controllers也就是存放我们自己的业务文件

|--directives.js // 指令文件(指令可共用)

|--fliters.js // 过滤器文件(过滤器可共用)

|--services.js //  服务文件(可共用,一般是与服务器交互的服务)

|--partials

|--html1.html

|--html2.html

|--index.html

app.js

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

'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

?

1

2

3

4

5

6

7

8

9

10

11

'use strict'``;

/* Controllers */

angular.module(``'myApp.controllers'``, [])

.controller(``'MyCtrl1'``, [``'$scope'``, function``($scope) {

}])

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

}]);

directives.js

?

1

2

3

4

5

6

7

8

9

10

11

'use strict'``;

/* Directives */

angular.module(``'myApp.directives'``, []).

directive(``'appVersion'``, [``'version'``, function``(version) {

return function``(scope, elm, attrs) {

elm.text(version);

};

}]);

filters.js

?

1

2

3

4

5

6

7

8

9

10

'use strict'``;

/* Filters */

angular.module(``'myApp.filters'``, []).

filter(``'interpolate'``, [``'version'``, function``(version) {

return function``(text) {

return String(text).replace(/\%VERSION\%/mg, version);

};

}]);

services.js

?

1

2

3

4

5

6

7

8

9

'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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

<!DOCTYPE&nbsp;html>

<!--[``if lt&nbsp;IE&nbsp;7]>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<html&nbsp;ng-app=``"myApp" class``=``"no-js&nbsp;lt-ie9&nbsp;lt-ie8&nbsp;lt-ie7"``>&nbsp;<![endif]-->

<!--[``if IE&nbsp;7]>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<html&nbsp;ng-app=``"myApp" class``=``"no-js&nbsp;lt-ie9&nbsp;lt-ie8"``>&nbsp;<![endif]-->

<!--[``if IE&nbsp;8]>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<html&nbsp;ng-app=``"myApp" class``=``"no-js&nbsp;lt-ie9"``>&nbsp;<![endif]-->

<!--[``if gt&nbsp;IE&nbsp;8]><!-->&nbsp;<html&nbsp;ng-app=``"myApp"``>&nbsp;<!--<![endif]-->

<head>

<meta&nbsp;charset=``"utf-8"``>

<meta&nbsp;http-equiv=``"X-UA-Compatible" content=``"IE=edge"``>

<title>My&nbsp;AngularJS&nbsp;App</title>

<meta&nbsp;name=``"description" content=``""``>

<meta&nbsp;name=``"viewport" content=``"width=device-width,&nbsp;initial-scale=1"``>

<link&nbsp;rel=``"stylesheet" href=``"bower_components/html5-boilerplate/css/normalize.css"``>

<link&nbsp;rel=``"stylesheet" href=``"bower_components/html5-boilerplate/css/main.css"``>

<link&nbsp;rel=``"stylesheet" href=``"css/app.css"``/>

<script&nbsp;src=``"bower_components/html5-boilerplate/js/vendor/modernizr-2.6.2.min.js"``></script>

</head>

<body>

<ul>

<li><a&nbsp;href=``"#/view1"``>view1</a></li>

<li><a&nbsp;href=``"#/view2"``>view2</a></li>

</ul>

<!--[``if lt&nbsp;IE&nbsp;7]>

<p>You&nbsp;are&nbsp;using&nbsp;an&nbsp;<strong>outdated</strong>&nbsp;browser.&nbsp;Please&nbsp;<a&nbsp;href=``"http://browsehappy.com/"``>upgrade&nbsp;your&nbsp;browser</a>&nbsp;to&nbsp;improve&nbsp;your&nbsp;experience.</p>

<![endif]-->

<div&nbsp;ng-view></div>

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

<!--&nbsp;In&nbsp;production&nbsp;use:

<script&nbsp;src=``"//ajax.googleapis.com/ajax/libs/angularjs/x.x.x/angular.min.js"``></script>

-->

<script&nbsp;src=``"bower_components/angular/angular.js"``></script>

<script&nbsp;src=``"bower_components/angular-route/angular-route.js"``></script>

<script&nbsp;src=``"js/app.js"``></script>

<script&nbsp;src=``"js/services.js"``></script>

<script&nbsp;src=``"js/controllers.js"``></script>

<script&nbsp;src=``"js/filters.js"``></script>

<script&nbsp;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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

<!doctype&nbsp;html>

<html&nbsp;ng-app>

<head>

<title>Angular-RequireJS&nbsp;sample&nbsp;app</title>

<meta&nbsp;name=``"viewport" content=``"width=device-width,&nbsp;initial-scale=1.0"``>

<link&nbsp;rel=``"stylesheet" type=``"text/css" media=``"all" href=``"app/css/app.css" />

</head>

<body&nbsp;>

<h1>AngularJS&nbsp;+&nbsp;RequireJS</h1>

<ul>

<li><a&nbsp;href=``"#/view1"``>View&nbsp;1</a></li>

<li><a&nbsp;href=``"#/view2"``>View&nbsp;2</a></li>

</ul>

<div&nbsp;ng-view></div>

<script&nbsp;data-main=``"app/js/main" src=``"/bower_components/requirejs/require.js"``></script>

</body>

</html>

main.js

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

require.config({

paths:&nbsp;{

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:&nbsp;{

'angular' :&nbsp;{``'exports' : 'angular'``},

'angularRoute'``:&nbsp;[``'angular'``],

'angularMocks'``:&nbsp;{

deps:[``'angular'``],

'exports'``:``'angular.mock'

}

},

priority:&nbsp;[

"angular"

]

});

//http://code.angularjs.org/1.2.1/docs/guide/bootstrap#overview_deferred-bootstrap

window.name&nbsp;= "NG_DEFER_BOOTSTRAP!"``;

require(&nbsp;[

'angular'``,

'app'``,

'routes'

], function``(angular,&nbsp;app,&nbsp;routes)&nbsp;{

'use&nbsp;strict'``;

var $html&nbsp;=&nbsp;angular.element(document.getElementsByTagName(``'html'``)[0]);

angular.element().ready(``function``()&nbsp;{

angular.resumeBootstrap([app[``'name'``]]);

});

});

app.js

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

define([

'angular'``,

'filters'``,

'services'``,

'directives'``,

'controllers'``,

'angularRoute'``,

], function (angular,&nbsp;filters,&nbsp;services,&nbsp;directives,&nbsp;controllers)&nbsp;{

'use&nbsp;strict'``;

//&nbsp;Declare&nbsp;app&nbsp;level&nbsp;module&nbsp;which&nbsp;depends&nbsp;on&nbsp;filters,&nbsp;and&nbsp;services

return angular.module(``'myApp'``,&nbsp;[

'ngRoute'``,

'myApp.controllers'``,

'myApp.filters'``,

'myApp.services'``,

'myApp.directives'

]);

});

controllers.js

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

define([``'angular'``, 'services'``], function (angular)&nbsp;{

'use&nbsp;strict'``;

/*&nbsp;Controllers&nbsp;*/

return angular.module(``'myApp.controllers'``,&nbsp;[``'myApp.services'``])

//&nbsp;Sample&nbsp;controller&nbsp;where&nbsp;service&nbsp;is&nbsp;being&nbsp;used

.controller(``'MyCtrl1'``,&nbsp;[``'$scope'``, 'version'``, function ($scope,&nbsp;version)&nbsp;{

$scope.scopedAppVersion&nbsp;=&nbsp;version;

}])

//&nbsp;More&nbsp;involved&nbsp;example&nbsp;where&nbsp;controller&nbsp;is&nbsp;required&nbsp;from&nbsp;an&nbsp;external&nbsp;file

.controller(``'MyCtrl2'``,&nbsp;[``'$scope'``, '$injector'``, function``($scope,&nbsp;$injector)&nbsp;{

require([``'controllers/myctrl2'``], function``(myctrl2)&nbsp;{

//&nbsp;injector&nbsp;method&nbsp;takes&nbsp;an&nbsp;array&nbsp;of&nbsp;modules&nbsp;as&nbsp;the&nbsp;first&nbsp;argument

//&nbsp;if&nbsp;you&nbsp;want&nbsp;your&nbsp;controller&nbsp;to&nbsp;be&nbsp;able&nbsp;to&nbsp;use&nbsp;components&nbsp;from

//&nbsp;any&nbsp;of&nbsp;your&nbsp;other&nbsp;modules,&nbsp;make&nbsp;sure&nbsp;you&nbsp;include&nbsp;it&nbsp;together&nbsp;with&nbsp;'ng'

//&nbsp;Furthermore&nbsp;we&nbsp;need&nbsp;to&nbsp;pass&nbsp;on&nbsp;the&nbsp;$scope&nbsp;as&nbsp;it's&nbsp;unique&nbsp;to&nbsp;this&nbsp;controller

$injector.invoke(myctrl2, this``,&nbsp;{'$scope':&nbsp;$scope});

});

}]);

});

directives.js

?

1

2

3

4

5

6

7

8

9

10

11

12

define([``'angular'``, 'services'``], function``(angular,&nbsp;services)&nbsp;{

'use&nbsp;strict'``;

/*&nbsp;Directives&nbsp;*/

angular.module(``'myApp.directives'``,&nbsp;[``'myApp.services'``])

.directive(``'appVersion'``,&nbsp;[``'version'``, function``(version)&nbsp;{

return function``(scope,&nbsp;elm,&nbsp;attrs)&nbsp;{

elm.text(version);

};

}]);

});

filters.js

?

1

2

3

4

5

6

7

8

9

10

11

12

define([``'angular'``, 'services'``], function (angular,&nbsp;services)&nbsp;{

'use&nbsp;strict'``;

/*&nbsp;Filters&nbsp;*/

angular.module(``'myApp.filters'``,&nbsp;[``'myApp.services'``])

.filter(``'interpolate'``,&nbsp;[``'version'``, function``(version)&nbsp;{

return function``(text)&nbsp;{

return String(text).replace(/\%VERSION\%/mg,&nbsp;version);

};

}]);

});

routes.js

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

define([``'angular'``, 'app'``], function``(angular,&nbsp;app)&nbsp;{

'use&nbsp;strict'``;

return app.config([``'$routeProvider'``, function``($routeProvider)&nbsp;{

$routeProvider.when(``'/view1'``,&nbsp;{

templateUrl: 'app/partials/partial1.html'``,

controller: 'MyCtrl1'

});

$routeProvider.when(``'/view2'``,&nbsp;{

templateUrl: 'app/partials/partial2.html'``,

controller: 'MyCtrl2'

});

$routeProvider.otherwise({redirectTo: '/view1'``});

}]);

});

services.js

?

1

2

3

4

5

6

7

8

9

10

define([``'angular'``], function (angular)&nbsp;{

'use&nbsp;strict'``;

/*&nbsp;Services&nbsp;*/

//&nbsp;Demonstrate&nbsp;how&nbsp;to&nbsp;register&nbsp;services

//&nbsp;In&nbsp;this&nbsp;case&nbsp;it&nbsp;is&nbsp;a&nbsp;simple&nbsp;value&nbsp;service.

angular.module(``'myApp.services'``,&nbsp;[])

.value(``'version'``, '0.1'``);

});

controllers文件夹中一个单独controlle文件,myCtrl2.js

?

1

2

3

4

5

6

7

8

9

10

11

define([], function``()&nbsp;{

return [``'$scope'``, '$http'``, function``($scope,&nbsp;$http)&nbsp;{

//&nbsp;You&nbsp;can&nbsp;access&nbsp;the&nbsp;scope&nbsp;of&nbsp;the&nbsp;controller&nbsp;from&nbsp;here

$scope.welcomeMessage&nbsp;= 'hey&nbsp;this&nbsp;is&nbsp;myctrl2.js!'``;

//&nbsp;because&nbsp;this&nbsp;has&nbsp;happened&nbsp;asynchroneusly&nbsp;we've&nbsp;missed

//&nbsp;Angular's&nbsp;initial&nbsp;call&nbsp;to&nbsp;$apply&nbsp;after&nbsp;the&nbsp;controller&nbsp;has&nbsp;been&nbsp;loaded

//&nbsp;hence&nbsp;we&nbsp;need&nbsp;to&nbsp;explicityly&nbsp;call&nbsp;it&nbsp;at&nbsp;the&nbsp;end&nbsp;of&nbsp;our&nbsp;Controller&nbsp;constructor

$scope.$apply();

}];

});

结尾

写到这应该差不多了,就快超字数了.通常情况下Angular应用的构建这样就可以了,因为比起传统框架angular的代码量上肯定会有优势,所以一些不必要的东西就不用引入了.上面这些也是我在这段时间的项目中遇到并且做过的,已经实战过了,所以如果有类似需求的同学可以不必在此填坑.