前端架构:requirejs+angularjs实现懒加载angular模块
require.js + angular.js の一种前端架构
新项目要完全采用 restful api 的方式来进行开发,既然前端只有我一个就我说了算ԅ(≖‿≖ԅ),工作以来还未在项目中用过 angular 开发,先简单介绍一下 angular.js ,我理解的她是一种重型前端 mvc 框架,对写 jQuery 的人来说可能上手比较困难,不过一旦理解她的思想就容易了,她内部已经做了很多工作,用她来开发的话你要关心的是数据的变动,而不是像 jQuery 一样去操作 DOM 元素,如果你对 jQuery 很熟悉的话想上手 angular 我推荐理解一下 stackoverflow 上这个问题,__如果我对 jQuery 开发很熟如何理解 angular __。
requirejs 不用说都知道是用来前端懒加载 scripts 的,我在网上看到的使用 require + angular 的组合的案例模式都是一样的,无论你访问网站的哪个 url ,都会把 angular 的所有模块全部通过 require 加载下来,虽然 angular 与 backbone 这些框架貌似更适合做单页应用,但是我认为单页应用也没必要把所有的模块都加载下来,这样首屏加载就会很慢,用户体验很不好;于是我 google 了一通,终于找到了解决方法,通过 require 配合 angular route 的 resolve 方法,实现单模块加载,这样做的好处显而易见,坏处可以说没有,硬要说的话还是 angular 之前的缺点:seo 方面要单做。
废话不多说,show you my code:
首先项目目录结构是这样滴:
app-|
|-package.json
|-index.html
|-views
|-src-+
|-img
|-css
|-js-+
| |-controllers-+...
| |-services-+...
| +application.js
| +require-config.js
| +routeResolve.js
|-lib-+
+angular.min.js
+angular-route.min.js
+angular-animate.min.js
+angular-resourse.min.js
+require.js
index.html 长这样:
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8">
<title>application</title>
<script src="/src/lib/require.js" data-main="/src/js/require-config.js"></script>
</head>
<body ng-view></body>
</html>
require-config.js :
require.config({
baseUrl: '/src',
paths: {
'angular': 'lib/angular.min',
'ngRoute': 'lib/angular-route.min',
'ngAnimate': 'lib/angular-animate.min',
'ngResource': 'lib/angular-resource.min'
},
shim: {
angular: {
exports : 'angular'
},
ngRoute: {
deps: ['angular'],
exports: 'ngRoute'
},
ngAnimate: {
deps: ['angular'],
exports: 'ngAnimate'
},
ngResource: {
deps: ['angular'],
exports: 'ngResource'
}
}
,urlArgs: 'v='+(+new Date())
});
require([
'js/application'
], function(application){
angular.element(document).ready(function(){
angular.bootstrap(document, ['application']);
});
})
application.js :
define([
'angular',
'ngRoute',
'ngAnimate',
'ngResource',
'js/routeResolve'
], function( angular, ngRoute, ngAnimate, ngResource, routeResolver ) {
var application = angular.module('application', ['ngRoute', 'ngAnimate', 'ngResource']);
window.application = application;
application
.config(['$routeProvider', '$controllerProvider', '$compileProvider', '$filterProvider', '$provide',
function($routeProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
var route = routeResolver;
$routeProvider
.when('/', {
reloadOnSearch: false,
templateUrl:'views/index.html',
resolve: route.resolve([
'js/services/peopleService',
'js/controllers/popup',
'js/controllers/paginator',
'js/controllers/index'
])
})
.otherwise({
redirectTo:'/'
});
window.application.components = {
controller : $controllerProvider.register,
directive : $compileProvider.directive,
filter : $filterProvider.register,
factory : $provide.factory,
service : $provide.service
}
}]);
return application;
})
routeResolve.js :
define(function ( require ) {
return function () {
var resolve = function (deps, preFetchFuncs) {
var routeDef = {
load: ['$q', '$rootScope', function ($q, $rootScope) {
var dependencies = deps;
return resolveDependencies($q, $rootScope, dependencies);
}]
};
if ( preFetchFuncs ) {
angular.merge( routeDef, preFetchFuncs );
}
return routeDef;
},
resolveDependencies = function ($q, $rootScope, dependencies) {
var defer = $q.defer();
require(dependencies, function () {
defer.resolve();
$rootScope.$apply()
});
return defer.promise;
};
return {
resolve: resolve
}
}();
});
其实这就是所有的内容了,当访问首页即 ‘/‘ 时,angular route 的 resolve 方法__通过__我们封装的__routeResolve__来懒加载模块代码,当然模块代码写的时候就不是 define function
里再写 angular.controller
了,直接写 window.application.components.controller
,好那么问题来了,为什么要暴露 angular 的那些方法给 window 呢,原因是 angular 的工作方式,angular 在启动之后是不能动态添加 controller 啊 service 啊之类的,在 angular 程序启动后,要添加只能通过内部的 register 方法(controller 的 register),所以你懂的。
OK,采用这种架构之后,前端__所有__代码都可以扔到 cdn 上去了,接口全部 rest api。
以上。
(ps: 这种架构到底有哪些坑本人还不得而知,若有很明显的坑麻烦还请告知一下我(๑╹ڡ╹)╭)
参考链接: