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 ...
随机推荐
- Openstack组件实现原理 — Nova 体系结构
目录 目录 前文列表 Nova体系结构 虚拟机实例化流程 前文列表 Openstack组件部署 - Overview和前期环境准备 Openstack组建部署 - Environment of Con ...
- ThreeJS模型展示为黑色,模型出不来
选取gltf格式时,出现模型为黑色,模型出不来 原因: 我们设计部可能是用maya或者3dmax去做:在模型导出时,没有gltf格式:如果maya或者3dmax导出obj然后导进blender,再导出 ...
- 4-vim-工作模式-01-职责以及切换模式
vi 有三种工作模式 1.命令模式 打开文件首先进入命令模式,是使用vi的入口. 通过命令对文件进行常规的编辑操作,例如:定位-翻页-复制-粘贴-删除等. 在其他图形编辑器下,通过快捷键或鼠标实现的操 ...
- 一键抓取Android的Locat Log
很多小伙伴在做App测试时,一遇到Cash,开发同学最常说的一句话,就是抓下Locat日志,很多小伙伴一听到这个抓取日志就会觉得有点烦. 主要有2点: 1.是这个bug可能不好 ...
- ubuntu安装WPS替代office
安装 1.下载地址:http://community.wps.cn/download/(去WPS官网下载) 下载第一个即可 2.执行安装命令: sudo dpkg -i wps-office_10.1 ...
- MJExtension常用方法
一.MJExtension第三方框架 我们在iOS开发过程中,我们常常需要将字典数据(也就是JSON数据)与Model模型之间的转化,例如网络请求返回的微博数据.等等,如果我们自己全部手动去创建模型并 ...
- python 对象的删除
- C# 记录循环消耗时间
今天写了循环段代码,但是感觉好像性能很差的样子,就想看一下整个循环的执行时间,最开始我想到了DateTime.Now,但是诡异的是,如果我循环的次数比较少的话(少于30000次)就会发现2次时间间隔是 ...
- mysql数据分组
创建分组 分组是在SELECT语句中的GROUP BY 子句中建立的. 例: SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY ...
- vue 学习三 v-model 表单绑定输入 以及修饰符的用处
v-model 指定使用过vue的同学都应该是很熟悉的了,这里就不多介绍,本章主要就是记录一些v-model非常实用的修饰符和对于v-model在html文本框,多行文本框,选择框,单选框,复选框上对 ...