angularJS和requireJS和angularAMD
最近因为要用到angularJS开发项目,因为涉及到的静态资源比较多,所以想把js文件通过requireJS来按需加载,这两个框架以前都使用过,但是结合到一起还没有用过,那就试一下,看能否达到目的。
requireJS是为了实现js文件异步加载和管理模块之间依赖性的框架,详情请看阮一峰 require.js的用法和RequireJS 中文网这里就不做介绍了。
我们先来创建模版容器index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="js/require/require.js" data-main="js/main"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
唯一的一个js文件引入是require.js文件,这个是requireJS核心文件,这个script标签的属性data-main用来指定requireJS的入口文件,下方div是angularjs的dom容器,这里因为要用到angularjs的手动调用,所以不用在div上指定ng-app属性。
创建requireJS入口文件main.js
(function(){
require.config({
baseUrl : "js",
paths : {
"jquery" : "jquery/jquery-1.12.2.min",
"angular" : "angular/angular",
"angular-route" : "angular/angular-route",
"domReady" : "require/domReady",
"controllerModel" : "controller/controller"
},
shim : {
"angular" : {
exports : "angular"
},
"angular-route" : {
deps : ["angular"],
exports : "angular-route"
}
},
deps : ['app']
});
})();
- baseUrl 用来指定加载模块的目录,后期涉及到路径都以这个目录为相对路径。
- paths 指定模块的加载路径。
- shim 配置不兼容模块
- deps 指定依赖模块,requireJS会加载这个文件并执行。
我们现在的文件目录接口是这样的:
js文件目录是这样的 
创建angularJS执行文件app.js
接下来我们要创建angularJS模块并且配置路由然后通过内置方法bootstrap来手动触发angularJS。 app.js文件是通过requireJS来动态加载的,所以要按照AMD规范写。
(function(){
define(["angular","angular-route","mainController",'domReady!'],function(angular){
//创建angularJS模块
var app = angular.module("webapp",[
'ngRoute',
'webapp.controllers'
]);
//设置angularJS路由
app.config(function($routeProvider,$locationProvider){
$routeProvider.when("/",{
templateUrl : "tpl/sy.html",
controller : "syCtrl"
}).when("/login",{
templateUrl : "tpl/login.html",
controller : "loginCtrl"
});
$locationProvider.html5Mode(false).hashPrefix("!");
});
//手动触发angularJS
angular.bootstrap(document,['webapp']);
return app;
});
})();
app.js依赖的js模块有
- angular angularJS核心文件
- angular-route angularJS路由文件
- domReady! 这个是requireJS的插件可以让回调函数在页面DOM结构加载完成后再运行。
- mainController 这个是我们接下来要写的控制器
创建模版
在创建控制器前我们先创建下模版,按照上面路由描述,有两个页面一个是sy.html,一个是login.html,创建好这两个模版,并把他们放到tpl文件夹中。
sy.html
<h1>{{data}}</h1>
<a href="javascript:void(0)" ng-click="goLogin()">去login页面</a>
login.html
<h1>{{data}}</h1>
<a href="javascript:void(0)" ng-click="goSy()">去sy页面</a>
创建控制器mainController
在app.js文件中,通过requireJS加载mainController模块,mainController模块可以认为控制器的入口,这里去异步加载所有控制器。
按照路由描述规则,我们需要创建syCtrl和loginCtrl这两个控制器,并且添加到控制器入口文件mainController.js中。
mainController.js
(function(){
define([
'controller/syCtrl',
'controller/loginCtrl'
],function(){
});
})();
接下来我们创建syCtrl和loginCtrl这两个控制器,在创建这两个控制器前,我们先看下angularJS是怎么创建控制器的。
var angularController = angular.module("angularController",[]);
angularController.controller("ctrlName",function(){
});
从上面代码可以看出angularJS的控制器都是先创建angular模块,然后执行当前模块controller方法来绑定控制器,在app.js文件中创建的新模块依赖注入当前模块angularController。
在app.js文件中我们指定依赖的控制器模块是webapp.controllers。我们需要创建一个文件,这个文件是为所有控制器文件提供webapp.controller模块同时把所有控制器都绑定到webapp.controllers模块中,然后app.js文件中设置依赖注入后控制器就可以执行了。 我们创建controller文件夹放到js文件夹中,创建如下文件:
controller.js文件就是我们要创建的控制器模块公用文件,下方两个文件都是单个控制器文件,这两个文件都依赖controller.js提供的模块。
我们在main.js文件中配置controller.js名称是controllerModel所以在需要依赖controller.js都可以直接依赖controllerModel。
controller.js
(function(){
define(['angular'], function (angular) {
return angular.module('webapp.controllers', []);
});
})();
controllerModel模块返回创建的angularJS模块webapp.controllers,app.js文件中放到module方法第二个参数中设定依赖注入。
接下来我们再创建syCtrl.js和login.js文件
syCtrl.js
(function(){
define(['controllerModel'],function(controllers){
controllers.controller('syCtrl',function($scope,$location){
$scope.data = "我是sy";
$scope.goLogin = function(){
$location.path("/login")
}
})
})
})();
login.js
(function(){
define(['controllerModel'],function(controllers){
controllers.controller('loginCtrl',function($scope,$location){
$scope.data = "我是login";
$scope.goSy = function(){
$location.path("/")
}
})
})
})();
这两个控制器都依赖controllerModel,然后调用controllerModel模块的controller方法来创建控制器,剩下内容就是在控制器中绑定数据。
貌似搞砸了
完成上面所有步骤后,这个应用终于完成了,我们在打开页面看下效果
打开首页后是这样的
点击去login页面后跳转到login页面
然后点击去sy页面也能跳转到sy页面
功能貌似没有问题,我要的按需加载实现了吗?我们看下文件的加载情况,我需要的功能是在访问sy页面的时候调用syCtrl控制器,访问login页面调用loginCtrl控制器。
可惜,在访问首页的时候控制器就全部被加载,这样的结果是必然的,因为我们通过requireJS加载控制器的时候mainController.js文件是将所有的控制器都加载过来的。而mainController.js模块在创建webapp模块的时候加载执行,只执行一次,所以必须将所有控制器加载并且绑定到webapp模块上。
我的本意是将各个控制器分成单独的文件,然后需要加载某个控制器的时候再去调用。在实际开发中,涉及到的模块太多的时候我们希望通过单独的文件来管理单独的模块,然后通过grunt等工具在线下合并成一个文件在生产环境中使用,这样合并后的文件如果很大的话会影响页面的加载速度,如果不合并的话请求数又会太多,所以通过requireJS来异步加载各个模块,我们上面所做的不是没有意义,毕竟我们解决了加载文件太大的问题。
angularAMD 实现按需加载
我们做了很多工作,但是没有解决最根本的问题——按需加载。接下来我们要解决这个问题。 我们用另外一个事例来简单说明angularJS控制器、服务的按需加载,指令的按需加载我认为没有必要,自定义的指令大多作为公用功能来处理,这样的功能本来就是全局的,所以在实创建angular模块的时候指定requireJS依赖关系直接调用就行。
安装
bower install angularAMD
bower install angular-ui-router
bower 会自动加载依赖的js文件,所有文件都放入bower_components文件夹 
创建模版文件和js入口文件
index.html
<!DOCTYPE html>
<html>
<head>
<!-- meta -->
<meta charset="utf-8">
<!-- title -->
<title></title>
<!-- script -->
<script data-main="main.js" src="bower_components/requirejs/require.js"></script>
</head>
<body>
<!-- content -->
<div ui-view></div>
</body>
</html>
模版文件和上次创建的模版文件一样,都是通过requireJS入口文件来处理接下来的工作。
main.js
(function(){
require.config({
paths: {
"angular": "bower_components/angular/angular",
"angular-ui-router": "bower_components/angular-ui-router/release/angular-ui-router",
"angularAMD": "bower_components/angularAMD/angularAMD",
"ngload": "bower_components/angularAMD/ngload"
},
shim: {
"angular": { exports: "angular" },
"angular-ui-router": ["angular"],
"angularAMD": ["angular"],
"ngload": ["angularAMD"]
},
deps : ["app"]
});
})();
main.js文件的内容还是和以前一样,配置好各个模块的url,并且指定依赖模块app.js文件,app.js是创建angularJS模块的入口。
接下来我们创建app.js文件
app.js
(function(){
define(["angular", "angularAMD", "angular-ui-router"], function (angular, angularAMD) {
//设置路由
var registerRoutes = function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/home");
$stateProvider
// home
.state("home", angularAMD.route({
url: "/home",
templateUrl: "home.html",
controllerUrl: "home.js"
}))
// home
.state("about", angularAMD.route({
url: "/about",
templateUrl: "about.html",
controllerUrl: "about.js"
}))
;
};
//实例化angularJS
var app = angular.module("app", ["ui.router"]);
//配置
app.config(["$stateProvider", "$urlRouterProvider", registerRoutes]);
//手动启动angularJS 并返回angularJS实例对象
return angularAMD.bootstrap(app);
});
})();
我们这里创建的app.js文件和前文说道的app.js文件功能一样,唯一的区别是依赖的模块内容变化,同样在使用对应模块的时候也是不一样的,但是实现的功能是一样的。
同时这里需要注意,配置路由的时候,不光要指定ur和模版url还要指定每个模版对应的控制器的url
没错,这样简单的配置就可以实现控制器的按需加载。我们访问home页面angularJS会自动加载home.html模版和home.js控制器,加载完成后的执行方式和前边是一样的。
添加模版文件home.html和控制器文件home.js
home.html
<h1>{{ title }}</h1>
<br/>
<button ui-sref="about">About</button>
home.js
(function(){
define([], function () {
return ["$scope", function ($scope) {
$scope.title = "This is Home page";
}];
});
})();
home.js是home控制器,可以看到写法和方法的sy控制器、login控制器都不一样,首先通过requrieJS来确定依赖模块,然后在回调函数返回数组,数组的最后一个元素是控制器的执行函数,前边的都是控制器需要加载的服务,其实返回值就是创建控制器函数controller的第二个参数,第一个参数是控制器名称,这个应该是内部自动指定了。
这样我们第一个路由就创建好了,访问页面如图
添加about模版文件about.html和控制器about.js
about.html
<h1>{{ title }}</h1>
<h1>{{ user.name}}</h1>
<br/>
<button ui-sref="home">Home</button>
about.js
(function(){
define([], function () {
return ["$scope", function ($scope) {
$scope.title = "This is About page";
$scope.user = "tudou";
}];
});
})();
about.js和html.js内容一样,不做解释了。
控制器按需加载了
访问home页面js资源加载情况如下
前面的文件是依赖模块加载,home.js和home.html是当前页面需要的模版和资源,没有加载about页面的内容,我们点击按钮去about页面看下。
可以看到在about页面新加载了两个文件about.js和about.html
我们controller的按需加载实现了,接下来我们要实现服务的按需加载
服务按需加载
创建服务UserRepository.js文件
(function(){
define(["app"],function(app){
app.factory("UserRepository", function(){
return {name:"tudou"};
});
});
})();
服务的创建依赖angularJS模块,上文是在controller/controller.js中创建了一个专门针对控制器的angularJS模块,这次我们直接调用app.js返回的angularJS模块,原理和上文说到的一样。 执行模块的factory方法申明一个服务,这个服务就生成了。
调用服务
其实在创建about.js和home.js时我们已经调用了$scope服务,不过$scope服务是angularJS内置的服务,所以我们要调用自定义服务需要先加载文件,然后在申明调用的服务传递到控制器里面就可以直接使用了。 在define方法的第一个参数中声明依赖的js文件,在回调函数返回的数组中申明服务,about.js修改成下方代码
(function(){
define(["UserRepository"], function (UserRepository) {
return ["$scope", "UserRepository",function ($scope,UserRepository) {
$scope.title = "This is About page";
console.log(UserRepository);
$scope.user = UserRepository;
}];
});
})();
这样我们angularJS控制器和服务的按需加载就完成了。还有过滤器的模块化应该和服务是一样的。
angularJS和requireJS和angularAMD的更多相关文章
- Integrating AngularJS with RequireJS
Integrating AngularJS with RequireJS When I first started developing with AngularJS keeping my contr ...
- AngularJS与RequireJS集成方案
关于angularjs.requirejs的基础知识请自行学习 一.简单事例的项目目录如下: -index.html -scripts文件夹 --controller文件夹 --- mianContr ...
- 基于angularJS和requireJS的前端架构
1.概要描述 1.1.angularJS描述:angularJS是可以用来构建WEB应用的,WEB应用中的一种端对端的完整解决方案.通过开发者呈现一个更高层次的抽象来简化应用的开发.最适合的就是用它来 ...
- AngularJS - 使用RequireJS还是Browserify?
http://www.html-js.com/article/2126 AngularJS - 使用RequireJS还是Browserify? AngularJS之所以吸引了很多开发者的关注,很大一 ...
- AngularJS + ui-router + RequireJS异步加载注册controller/directive/filter/service
一般情况下我们会将项目所用到的controller/directive/filter/sercive预先加载完再初始化AngularJS模块,但是当项目比较复杂的情况下,应该是打开对应的界面才加载对应 ...
- angularjs集成requirejs
其实说成使用requirejs加载angularjs应用会更贴切一些 <body> <span ng-controller="homeController"> ...
- AngularJS结合RequireJS做文件合并压缩的那些坑
我在项目使用了AngularJS框架,用RequireJS做异步模块加载(AMD),在做文件合并压缩时,遇到了一些坑,有些只是解决了,但不明白原因. 那些坑 1. build.js里面的paths必须 ...
- 从Java的角度理解前端框架,nodejs,reactjs,angularjs,requirejs,seajs
[前端神秘的面纱] 对后端开发来说,前端是神秘的, 眼花缭乱的技术,繁多的框架, 如果你还停留在前端等于只用jquery做开发,那么你out了, 本文从Java的角度简述下目前前端流行的一些框架. 水 ...
- 新建一个angularjs+requirejs+bootstrap+typescript+gulp+vscode+git的项目
环境 windows 10 准备工具 Visual Studio Code Node.js Git 需求 必须支持IE8 步骤开始: 执行命令行工具 mkdir Demo && cd ...
随机推荐
- jQuery Validate (摘自官网)
jQuery Validate 插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求.该插件捆绑了一套有用的验证方法,包括 URL 和电子邮件验证 ...
- Extjs各版本的下载链接,包含ext3.4源码示例
最近在维护一个老平台,用的是ext3.4,老东西在网上找示例发现既然还有人收钱,谷歌了一下总算找到了一位免费的发布的,感谢 yipanbo 分享 Extjs的版本繁多,本文收集了Extjs各个版本的下 ...
- [bzoj2839]集合计数 题解 (组合数+容斥)
Description 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得 它们的交集的元素个数为K,求取法的方案数,答案模1000000007 ...
- Go语言TCP Socket编程
Golang的主要 设计目标之一就是面向大规模后端服务程序,网络通信这块是服务端 程序必不可少也是至关重要的一部分.在日常应用中,我们也可以看到Go中的net以及其subdirectories下的 ...
- SpringBoot中配置不序列化返回值为null的属性
package com.weiresearch.properties; import com.fasterxml.jackson.annotation.JsonInclude;import com.f ...
- equals与==的区分
equals与==的区分 对于比较数值 public class Test { public static void main(String[] args){ int a=30; int b=30; ...
- 2、获取APP CPU占用率
前面已经介绍过如何获取包名和主活动名.这里不再过多赘述.我们依旧采取两种方案实现APP CPU占有率 Windows下获取APP CPU占用率 adb shell "dumpsys cpui ...
- vant实现三级联动
首先要在vant 框架里边 复制一下 省市区的 地址数据在这里下载eare.js 格式 : var address = { province_list: { 110000: '北京市', }, ...
- export 与 export default
export 和 import 都属于 ES6 的内容. node 的 module 遵循的是 CommonJS规范,requirejs遵循AMD,seajs遵循CMD,虽各有不同, 但总之还是希望保 ...
- Python的datetime模块使用
两个常量 MAXYEAR:9999 MINYEAR:1 五个类 datetime.datetime:日期时间类 datetime.date:日期类 datetime.time:时间类 datetime ...