前言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