文档章节

Angular项目构建指南 - 不再为angular构建而犹豫不决

顽Shi
 顽Shi
发布于 2014/06/16 23:20
字数 2509
阅读 16854
收藏 179

    前言

    接触Angular也有小半个月了,虽然没有使劲折腾,不过正所谓"no zuo no die".学一门新东西,不好好折腾一下总觉得对不起祖国,最不起人民...好像扯远了,想写前言来着.为什么要写这篇构建指南?最大的原因是为了给正在找这方面资料,挣扎于各种说法中的同学一个借鉴,同时我也把自己的经验记录下来,两全其美.

    正文

    如果你不知道什么是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自己会去处理.

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

© 著作权归作者所有

共有 人打赏支持
顽Shi
粉丝 274
博文 81
码字总数 92387
作品 0
普陀
程序员
加载中

评论(16)

NMTuan
NMTuan
我写了个自动路由.但还不完善.想异步加载controller.试着用script.js.但没成功...
求指点:http://git.oschina.net/nmtuan/angular.js-autoRoute
p
penJunTan
异步加载是手段 目的是按需加载..
按需加载还没做到哦
第三方支付接口
第三方支付接口
nej模块化开发
归丶海
归丶海
mark.
hantsy
hantsy

引用来自“成熟的毛毛虫”的评论

也可以下载个angularjs seed project,不是么?
这代码基本上就是 AngularJS Seed,官方的。
沫小依
沫小依
受用了81
开源中国匿名会员
开源中国匿名会员

引用来自“木木”的评论

用ExtJs,纯MVC架构
MVVM 架构,个人以为比 MVC 好用。
朝花夕拾杯中酒
用ExtJs,纯MVC架构
开源中国匿名会员
开源中国匿名会员

引用来自“开源中国匿名会员”的评论

用 yeoman 只要 yo angular ... 就快速建好了……

引用来自“顽Shi”的评论

自动化构建这个看不少人推荐,不过总是感觉无爱,还是喜欢自己弄

引用来自“hantsy”的评论

Grunt 在 Windows 下问题太多。
还行,就是要写配置,这个太烦了。
hantsy
hantsy
要看 AngluarJS 实例,可以上我的 GITHUB

https://github.com/hantsy

有多种后端 REST API 实例,包括CRUD,和 Authentication等。
Angular 6.0正式版发布,都有哪些新功能

点击关注异步图书,置顶公众号 每天与你分享IT好书 技术干货 职场知识 在Angular 5发布半年之后,Angular 6在昨天正式发布,那么在这个版本有哪些新功能呢?新版本重点关注工具链以及工具链在...

异步社区
05/08
0
0
使用Yeoman快速构建基于angular的web应用

前言 最近在学习使用安哥拉(angular.js)编写web应用,看了一些网友实践了解到yeoman,这个工具实在太好用了,必须在这里介绍一下。 angular 首先简单介绍一下angular,它是由google开源的一套...

snakelxc
2013/08/25
0
0
使用Yeoman快速构建基于angular的web应用

前言 最近在学习使用安哥拉(angular.js)编写web应用,看了一些网友实践了解到yeoman,这个工具实在太好用了,必须在这里介绍一下。 angular 首先简单介绍一下angular,它是由google开源的一套...

kisops
2013/08/25
0
0
Angular 6正式版发布,都有哪些新功能

在Angular 5发布半年之后,Angular 6在昨天正式发布,那么在这个版本有哪些新功能呢?新版本重点关注工具链以及工具链在 Angular 中的运行速度问题。除此之外,这次更新还包括框架包(@angu...

code_xzh
05/05
0
0
Angular 实战教程 - Today 系列文章目录

Angular 实战教程 - Today 系列文章目录 发布于 10:15 文章被以下专栏收录

小温
07/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

白话SpringCloud | 第五章:服务容错保护(Hystrix)

前言 前一章节,我们知道了如何利用RestTemplate+Ribbon和Feign的方式进行服务的调用。在微服务架构中,一个服务可能会调用很多的其他微服务应用,虽然做了多集群部署,但可能还会存在诸如网...

oKong
17分钟前
0
0
【解惑】领略Java内部类的“内部”

内部类有两种情况: (1) 在类中定义一个类(私有内部类,静态内部类) (2) 在方法中定义一个类(局部内部类,匿名内部类) 1、私有内部类 —— 在方法之间定义的内部类,非静态 我们首先看看类中...

偶尔诗文
59分钟前
1
0
sqlserver 2008 r2 直接下载地址(百度云)

之前下载的sqlserver2008发现不能附加,就卸载了,重新找到了sqlserver2008R2的百度云资源 卸载sqlserver2008还是有点麻烦,不过就是需要删除注册表中的信息 自己来回卸载了3次终于重装sqlse...

dillonxiao
今天
1
0
[Java]JVM调优总结 -Xms -Xmx -Xmn -Xss

JVM调优总结 -Xms -Xmx -Xmn -Xss 博客分类: Java General JVM应用服务器电信CMS算法 堆大小设置 JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可...

morpheusWB
今天
2
0
C++ std::function 和 std::bind

C++11提供了std::function和std::bind两个工具,用于引用可调用对象。这些可调用对象包括 普通函数,Lambda表达式,类的静态成员函数,非静态成员函数以及仿函数等。引用可调用对象,可以用于...

yepanl
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部