前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >按需加载 AngularJS 的 Controller

按需加载 AngularJS 的 Controller

作者头像
beginor
发布2020-08-10 14:44:22
1.2K0
发布2020-08-10 14:44:22
举报

按需加载 AngularJS 的 Controller

多视图应用

AngularJS 通过路由支持多视图应用, 可以根据路由动态加载所需的视图, 在 AngularJS 的文档中有详细的介绍, 网上也有不少教程, 就不用介绍了!

随着视图的不断增加, js文件 会越来越多, 而 AngularJS 默认需要把全部的 js 都一次性加载, 使用起来非常不便, 因此按需加载模块的需求会越来越强, 不过, AngularJS 并没有实现按需加载。

异步加载

关于异步加载, AngularJS 的开发指南中有这样一段话

Modules are a way of managing $injector configuration, and have nothing to do with loading of scripts into a VM. There are existing projects which deal with script loading, which may be used with Angular. Because modules do nothing at load time they can be loaded into the VM in any order and thus script loaders can take advantage of this property and parallelize the loading process.

这段话的大意是说 AngularJS 的模块只关注依赖注入,不关注脚本是怎么加载的。 目前已经有项目来处理脚本加载, 可以和 AngularJS 一起使用。 模块在加载的过程中什么都没做, 可以按照任意顺序加载, 因此脚本加载器可以使用这个特性进行并发加载。

AngularJS 在 $routeProvider文档中, when 方法的 route 参数有这样一个属性:

  • resolve - {Object.<string, function>=} - An optional map of dependencies which should be injected into the controller. If any of these dependencies are promises, the router will wait for them all to be resolved or one to be rejected before the controller is instantiated.

routeresolve 参数是一个可选依赖的 map 对象, 如果这个对象有成员是 promise 对象, 路由就会等待 promise 对象完成再初始化 controller 。

可以通过这一点, 来刻意创建一个 promise 对象加载需要的模块, 比如下面的代码:

代码语言:javascript
复制
$routeProvider.when('/myView', {
    controller: 'MyController',
    templateUrl: '/views/myView.html',
    resolve: {
        deps: function($q, $rootScope) {
            var defered = $q.defer();
            require(dependencies, function() {
                $rootScope.$apply(function() {
                    defered.resolve();
                });
            });
            return defered.promise;
        }
    }
});

为此, 可以单独写一个 loader.js 来生成 promise 对象, 代码如下:

代码语言:javascript
复制
define([], function() {
    return function(dependencies) {
        // 返回路由的 resolve 定义, 
        var definition = {
            // resolver 是一个函数, 返回一个 promise 对象;
            resolver: ['$q', '$rootScope', function($q, $rootScope) {
                // 创建一个延迟执行的 promise 对象
                var defered = $q.defer();
                // 使用 requirejs 的 require 方法加载的脚本
                require(dependencies, function() {
                    $rootScope.$apply(function() {
                        // 加载完脚本之后, 完成 promise 对象;
                        defered.resolve();
                    });
                });
                返回延迟执行的 promise 对象, route 会等待 promise 对象完成
                return defered.promise;
            }]
        };
        return definition;
    }
});

将应用的路由单独放在一个 route.js 文件中进行定义:

代码语言:javascript
复制
define([], function () {
    return {
        defaultRoute: '/welcome',
        routes: {
            '/welcome': {
                templateUrl: 'components/welcome/welcomeView.html',
                controller: 'WelcomeController',
                dependencies: ['components/welcome/welcomeController']
            },
            '/dialogs': {
                templateUrl: 'components/dialogs/dialogsView.html',
                controller: 'DialogsController',
                dependencies: ['components/dialogs/dialogsController']
            },
            '/list': {
                templateUrl: 'components/list/listView.html',
                controller: 'ListController',
                dependencies: ['components/list/listController']
            },
            '/user': {
                templateUrl: 'components/user/userView.html',
                controller: 'UserController',
                dependencies: ['components/user/userController']
            },
            '/help': {
                templateUrl: 'components/help/helpView.html',
                controller: 'HelpController',
                dependencies: ['components/help/helpController']
            }
        }
    };
});

$routeProvider 根据上面的定义进行初始化:

代码语言:javascript
复制
if (routeConfig.routes != undefined) {
    angular.forEach(routeConfig.routes, function(route, path) {
        $routeProvider.when(path, {
            templateUrl: route.templateUrl,
            controller: route.controller,
            // 设置每个路由的 resolve , 使用 requirejs 加载 controller 脚本
            resolve: loader(route.dependencies)
        });
    });
}

if (routeConfig.defaultRoute != undefined) {
    $routeProvider.otherwise({ redirectTo: routeConfig.defaultRoute });
}

手工注册 Controller

对于动态加载下来的 Controller 需要手工注册, 这就需要调用 $controllerProviderregister 方法, 为了方便使用, 可以定义一个全局的 app 对象, 将 AngularJS 的注册 controller 、 directive 、 filter 、 factory 、 service 方法都暴露出来, 代码如下:

代码语言:javascript
复制
define(['app.routes', 'app.loader', 'angular', 'angular-route'], function (config, loader) {
    'use strict';

    var app = angular.module('app', ['ngRoute', 'ngResource', 'ui.bootstrap']);
    app.config(configure);

    configure.$inject = ['$routeProvider', '$locationProvider', '$controllerProvider', '$compileProvider', '$filterProvider', '$provide'];

    return app;

    function configure($routeProvider, $locationProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
        app.registerController = $controllerProvider.register;
        app.registerDirective = $compileProvider.directive;
        app.registerFilter = $filterProvider.register;
        app.registerFactory = $provide.factory;
        app.registerService = $provide.service;
    }
});

有了这个 app 之后, 要做动态加载的 controller 就可以这样写了:

代码语言:javascript
复制
// 将 controller 定义为一个 AMD 模块, 依赖上面的 app
define(['app'], function(app) {
    'use strict';
    // 调用 app 暴露的 registerController 方法注册 controller
    app.registerController('HelpController', HelpController);
    // 定义 controller 的注入对象;
    HelpController.$inject = ['$scope'];
    // controller 具体实现
    function HelpController($scope) {
        $scope.greeting = 'Help Info';
    }
});

点击这里查看完整的例子 https://github.com/beginor/html-app-demo/tree/master/www

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 按需加载 AngularJS 的 Controller
    • 多视图应用
      • 异步加载
        • 手工注册 Controller
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档