require怎么加载angularjs指令require的路由

4被浏览210分享邀请回答0添加评论分享收藏感谢收起0添加评论分享收藏感谢收起AngularJS+RequireJS+AngularAMD实现按需加载
@ 22:41:15
前两节笔记中学习了requireJs的基本用法,以及requireJs和AngularJs组合使用的方法,但是项目构建完成之后,我发现一个问题,就是加载路由模块的时候,会把所有的controller都加载完成,这个其实是不科学的,因为我打开一个项目的时候,首先看到的是首页,也就是说暂时只需要加载首页的controller、template和server即可,其他页面还没有去点击,所以暂时不用加载相关代码,这样可以提升性能。
比如我需要的功能是在访问sy页面的时候调用syCtrl控制器,访问login页面调用loginCtrl控制器。
我使用requireJs本来是想将各个controller分成单独的文件,然后需要加载某个控制器的时候再去调用。在实际开发中,涉及到的模块太多的时候我们希望通过单独的文件来管理单独的模块,这样的话,就算每个controller的代码很多,也不至于全部集中在一个文件里边,后期维护成本大大降低。
但是我相当于我之前只是做了前端代码模块化,暂时还没有实现&按需加载&。发现这个问题时候,这段时间我一直在寻找相关的解决方法。
通过angularAMD实现可以实现按需加载:
将AngularAMD.js下载放置到项目中,通过require的path属性配置地址,然后在shim属性里边配置与其他文件的依赖关系,这就算完成了第一步。
然后在路由router.js里边引入AngularAMD模块,其中一个路由配置方法如下:
define(['app', 'angularAMD'], function(app, angularAMD){
return app.config(['$urlRouterProvider', '$stateProvider', function($urlRouterProvider, $stateProvider){
$urlRouterProvider.otherwise('/index');
$stateProvider.state('index', angularAMD.route({
url : '/index',
templateUrl : indexPath
.state('nodeList', angularAMD.route({
url : '/nodeList',
templateUrl : nodeListPath,
controllerUrl : 'nodeListCtr'
然后controller中的代码如下:
*后台编辑文章angular控制器
define(['app'], function(app){
return ['$scope', '$http', '$stateParams', '$sce', function($scope, $http, $stateParams, $sce){
url : editNewsDataPath,
nid : $stateParams.nid
method : 'post'
}).then(function(result){
$scope.title = result.data[0].
$scope.content = $sce.trustAsHtml(result.data[0].content);
注意controller里边不需要再写控制器名称来,直接就是依赖注入相应的服务到数组中即可。
这个项目的源代码github地址:
或许你的朋友正在寻找这个问题的答案,赶紧分享给他吧!
WEB前端开发交流群最近因为要用到angularJS开发项目,因为涉及到的静态资源比较多,所以想把js文件通过requireJS来按需加载,这两个框架以前都使用过,但是结合到一起还没有用过,那就试一下,看能否达到目的。
requireJS是为了实现js文件异步加载和管理模块之间依赖性的框架,详情请看和这里就不做介绍了。
我们先来创建模版容器index.html
&!DOCTYPE html&
&title&&/title&
&script src="js/require/require.js" data-main="js/main"&&/script&
&div ng-view&&/div&
唯一的一个js文件引入是require.js文件,这个是requireJS核心文件,这个script标签的属性data-main用来指定requireJS的入口文件,下方div是angularjs的dom容器,这里因为要用到angularjs的手动调用,所以不用在div上指定ng-app属性。
创建requireJS入口文件main.js
(function(){
require.config({
baseUrl : "js",
"jquery" : "jquery/jquery-1.12.2.min",
"angular" : "angular/angular",
"angular-route" : "angular/angular-route",
"domReady" : "require/domReady",
"controllerModel" : "controller/controller"
"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']);
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(){
'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文件
(function(){
define(['controllerModel'],function(controllers){
controllers.controller('syCtrl',function($scope,$location){
$scope.data = "我是sy";
$scope.goLogin = function(){
$location.path("/login")
(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&
&!-- meta --&
&meta charset="utf-8"&
&!-- title --&
&title&&/title&
&!-- script --&
&script data-main="main.js" src="bower_components/requirejs/require.js"&&/script&
&!-- content --&
&div ui-view&&/div&
模版文件和上次创建的模版文件一样,都是通过requireJS入口文件来处理接下来的工作。&main.js
(function(){
require.config({
"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"
"angular": { exports: "angular" },
"angular-ui-router": ["angular"],
"angularAMD": ["angular"],
"ngload": ["angularAMD"]
deps : ["app"]
main.js文件的内容还是和以前一样,配置好各个模块的url,并且指定依赖模块app.js文件,app.js是创建angularJS模块的入口。
接下来我们创建app.js文件
(function(){
define(["angular", "angularAMD", "angular-ui-router"], function (angular, angularAMD) {
//设置路由
var registerRoutes = function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/home");
$stateProvider
.state("home", angularAMD.route({
url: "/home",
templateUrl: "home.html",
controllerUrl: "home.js"
.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
&h1&{{ title }}&/h1&
&button ui-sref="about"&About&/button&
(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&
&button ui-sref="home"&Home&/button&
(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 = UserR
这样我们angularJS控制器和服务的按需加载就完成了。还有过滤器的模块化应该和服务是一样的。
阅读(...) 评论()本文主要说明在用AngularJS开发web应用中如何实现lazyload,使用AngularJS需要在前端实现路由功能,本文就介绍利用此点实现前端资源的懒加载。
目前大部分AngularJS的应用用requirJS组织模块,但是很多都没有使用lazyload功能,在app.js中启动时将全部依赖加载进来,在模块功能较少,前端资源少的情况下没问题。那么问题来了,依赖资源过多时怎么办?
build时利用grunt-contrib-requirejs提取合并文件,减少http请求,但是存在问题:build后文件大;线上调试不方便,尤其在html2js后问题更明显。
开发中尽量在原有文件里进行新业务添加,不增加额外的http请求压力,但是存在问题:多人合作时需要经常处理代码冲突;单个文件(control,directive等)很大,看的是眼花缭乱,容易出问题。
基本思路:在路由切换时加载所需要资源。工具:Angular-ui-router,oclazyload,requirejs。
配置oclazyload在引入oclazyload文件后配置主要参数项
app.config(['$ocLazyLoadProvider',function($ocLazyLoadProvider){
$ocLazyLoadProvider.config({
loadedModules: ['monitorApp'],//主模块名,和ng.bootstrap(document, ['monitorApp'])相同
jsLoader: requirejs, //使用requirejs去加载文件
files: ['modules/summary','modules/appEngine','modules/alarm','modules/database'], //主模块需要的资源,这里主要子模块的声明文件
debug: true
配置ui-route利用angularjs-ui-route配置路由跳转的基本规则和需要懒加载文件
app.config(['$stateProvider', '$urlRouterProvider',function($stateProvider, $urlRouterProvider){
* 路由切换时调用
* @param param.file 懒加载文件数组
* @param tpl 子模块view视图
* @param module 子模块名
function resovleDep(param,tpl,module){
var resolves = {
loadMyCtrl: ['$ocLazyLoad', '$templateCache', '$q', function($ocLazyLoad,$templateCache,$q) {
lazyDeferred = $q.defer();
return $ocLazyLoad.load({
name : module,
cache: false,
files: param.files
}).then(function() {
lazyDeferred.resolve($templateCache.get(tpl));
$urlRouterProvider.otherwise('/summary');
//路由配置
$stateProvider
.state('module1', {
url:'/module1',
templateProvider: function() { return lazyDeferred. },
controller: 'module1Controller',
resolve : resovleDep({files:[
'controllers/module1Ctrl',
'services/module1Service',
'directives/module1Directive'
]}, 'views/module1.html', 'app.module1')
.state('module2', {
abstract: true,
url: '/module2',
templateUrl: 'views/module2.html'
.state('module2.list', {
templateProvider: function() { return lazyDeferred. },
controller: 'module2Controller',
resolve : resovleDep({files:[
'controllers/module2ListCtrl',
'services/module2Service'
]}, 'views/list.html', 'app.module1')
.state('module1.detail', {
url: '/:id',
templateProvider: function() { return lazyDeferred. },
controller: 'detailController',
resolve : resovleDep({files:[
'controllers/detailCtrl',
'services/detailService'
]}, 'views/detail.html', 'app.module2')
ok,至此就可以在路由切换时方便的加载子模块和依赖资源,oclazyload和ui-router还有很多可挖掘的,大家可参考api满足需求。ps:最初用angular-route+oclazyload做时出现:
multiple directives asking for isolated scope on
multiple asking for template
等问题,不好用,建议使用ui-route,强大的多。
阅读(...) 评论()}

我要回帖

更多关于 angular4 require 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信