angularjs + ionic 实现项目的按需加载

参考:

ionic入门教程第十六课-在微信中使用ionic的解决方案(按需加载加强版)作者有一系列的ionic教程,很不错!

AngularJS模块详解

 

自己的demo:

angularjs-ionic-demo 

demo中的READE.md写的比较混乱,可以忽略不看

ionic自带使用gulp压缩文件可以查看gulpfile.js文件(里面有我添加的基本task,要使用gulp还要安装相应依赖项哦!),至于项目只看www文件就可以了

 

背景:

一开始使用angularjs+ionic做项目,并没有什么经验,只能是把东西拼凑在一起,能完成任务就行。但是做到后面发现,在首页一进去加载的时候所有的东西都会被一次性加载出来,这就导致加载时间很长。

当项目需求开始趋于稳定的时候,决定重做项目:按需加载页面,样式和js

 

开始按需加载:

这里就不赘述项目的生成等过程了,简单的使用Ionic Lab就可以创建3种不同的项目

1、在app.js中定义懒加载服务

当然要在首页引入ocLazyLoad.min.js,这一点儿别忘记

var app = angular.module('starter', ['ionic', 'oc.lazyLoad'])

 

2、设置所有的js文件(控制器,自定义指令,过滤器等)都支持按需加载

.config(['$stateProvider', '$ionicConfigProvider','$urlRouterProvider', '$controllerProvider', '$compileProvider', '$filterProvider', '$provide', '$ocLazyLoadProvider', "$locationProvider", 'JS_REQUIRES',
    function($stateProvider,$ionicConfigProvider, $urlRouterProvider, $controllerProvider, $compileProvider, $filterProvider, $provide, $ocLazyLoadProvider, $locationProvider, jsRequires) {
  // 主要代码(框架自带的懒加载的解决方案)
   app.controller
= $controllerProvider.register; app.directive = $compileProvider.directive; app.filter = $filterProvider.register; app.factory = $provide.factory; app.service = $provide.service; app.constant = $provide.constant; app.value = $provide.value; $stateProvider ...// 路由等代码 }]);
// JS_REQUIRES是自定义的在配置表里面定义的,算是静态变量
 

 3、配置表文件(实现js和css的按需加载),在项目中我命名为config放在js文件夹下,记得在首页中引用该文件

'use strict';

// 使用$provide.constant来定义了一个静态变量(见app.js中的config的配置)
app.constant('JS_REQUIRES', {
    //*** Scripts
    scripts: {
        //*** Controllers
        'TestCtrl':"js/controllers/TestCtrl.js",
        //*** Services
        'HttpService':"js/services/HttpService.js"
        //*** Filter
        'SetDataTimeFilter': "js/filter/SetDataTimeFilter.js",
        //*** Directive
        'StarDirective': "js/directive/Star.js",
        //*** 第三方
        // 复制文本到剪贴板
        'clipboard': "js/other/clipboard.min.js",
    },
    CssArg:{
      TestStyle: 'css/test.css',
    },
  // 把业务员相关联的文件按照界面写成分组,这样在代码中就不用把太多的精力放在文件关联上 ViewArgs: { TestArgs: [
'TestCtrl', 'HttpService', 'SetDataTimeFilter', 'TestStyle'] } });

 

4、拆分js文件

在www/js下新建controllers(控制器)、services(服务)、directive(指令)、filter(过滤器)等文件

以TestCtrl文件(controller)为例:

‘use strict’; // 使用严格模式

app.controller('TestCtrl', ["$scope", function(){
   ...
}]);

// 这里使用的app.controller其实是使用了$controllerProvider.register

 

相应的:

services文件使用app.factory

directive文件使用app.directive

filter文件使用app.filter

4、使用oclazyload和$q的组合实现动态加载文件

.config(['$stateProvider', '$ionicConfigProvider','$urlRouterProvider', '$controllerProvider', '$compileProvider', '$filterProvider', '$provide', '$ocLazyLoadProvider', "$locationProvider", 'JS_REQUIRES',
    function($stateProvider,$ionicConfigProvider, $urlRouterProvider, $controllerProvider, $compileProvider, $filterProvider, $provide, $ocLazyLoadProvider, $locationProvider, jsRequires) {
    
    //第一步的配置代码

  //配置路由 $stateProvider .state('test', { url: '/test', templateUrl: 'templates/test.html', prefetchTemplate:false, // 不会提前加载html(实现html页面的按需加载) controller: 'TestCtrl', resolve: loadSequence('TestArgs') /* 只关联少量文件时,可以写上所有的文件【loadSequence('ChatsCtrl','ChatsService')】; 或者文件比较多的时候,写上关联的模块名称 */ $urlRouterProvider.otherwise('/home'); function loadSequence() { var _args = arguments; // 传不传参数都能匹配到 var viewArgs = repeatArgs(_args[0]); //先匹配模块的,没有再匹配单文件的 if(viewArgs){ // 先匹配模块,找到就把模块对应的单文件列表返回给它,找不到就当做是单文件列表 _args = viewArgs }else{ //console.log("没有找到模块?") } function repeatArgs(name){ return jsRequires.ViewArgs[name]; } return { // 使用oclazyload和$q的组合实现懒加载 deps: ['$ocLazyLoad', '$q', function ($ocLL, $q) { var promise = $q.when(1); for (var i = 0, len = _args.length; i < len; i++) { promise = promiseThen(_args[i]); } return promise; function promiseThen(_arg) { if (typeof _arg == 'function') return promise.then(_arg); else return promise.then(function () { var nowLoad = requiredData(_arg); if (!nowLoad) return console.log('找不到文件 [' + _arg + ']'); return $ocLL.load(nowLoad); }); } function requiredData(name) { if (jsRequires.modules) for (var m in jsRequires.modules) if (jsRequires.modules[m].name && jsRequires.modules[m].name === name) return jsRequires.modules[m]; if(jsRequires.scripts && jsRequires.scripts[name]){ return jsRequires.scripts[name]; }else if(jsRequires.CssArg && jsRequires.CssArg[name]){ return jsRequires.CssArg[name]; } // return jsRequires.scripts && jsRequires.scripts[name]; } }]};} })

 

 

 

到此,我们想要的基本实现了。首次加载的时候只加载需要的文件,切换页面再加载其他文件。后面自行添加具体的功能就可以了

 

5、压缩

可以使用gulp压缩文件到一个单独的文件夹,记得把lib和index.html文件放进去。直接把访问地址中的www改成相应的名称就可以了。

前端构建工具gulpjs的使用介绍及技巧

 

 

了解angularjs,主要针对上面的第二步进行讲解,如果对代码没有问题可忽略

1、模块

angular模块通过angular.module(name, requires, configFn)方法生成:

  • 参数name是模块名称;
  • 参数requires标识依赖模块数组。如果不设置requires参数,调用angular.module(name)方法表示获取这个模块;因此,如果确定新模块没有依赖关系,必须设置requires为空数组[];
  • 参数configFn是方法或数组,负责在模块初始化时做一些配置,如果是数组,最后一个元素必须是方法

已经初始化的angular模块保存在一个叫modules的缓存对象中,key是模块名,value是模块对象。所以,定义一个同名的模块,等于覆盖之前的模块

2、服务注入

angular模块只保留服务的定义。

服务提供商,在Angular中称为Provider,几乎所有的服务(除了$injector)都是由服务提供商供应。无论是服务还是服务提供商,他们在Angular中都是唯一的,服务和服务提供商是一个一对一的关系。

所以整个过程:

  • 模块定义服务、服务提供商;
  • 注入器根据模块依赖关系加载模块,实例化所有服务提供商;
  • 应用需要服务,注入器根据服务名寻找服务提供商,服务提供商实例化服务;

每个angular模块内置有三个数组:

  • invokeQueue保存如何注入服务提供商和值的信息;
  • configBlocks保存模块的配置信息;
  • runBlocks保存这个模块的执行信息

模块被使用的时候,注入器根据invokeQueue中的信息,实例化服务提供商;根据configBlocks中的信息对服务提供商做一些额外的处理;根据runBlocks中提供的信息,调用前面的服务提供商提供的服务执行模块需要完成的工作。

angular模块提供了很多方法来填充这三个数组,比如config()、run()等。

例如:添加一个Controller:

angular.module('ngAppDemo',[])  
.controller('ngAppDemoController',function($scope) {  
      $scope.a= 1;  
      $scope.b = 2;  
});

这段代码等于:

invokeQueue.push(['$controllerProvider','register', ['ngAppDemoController', function(){}]]);

注入器根据这个信息,就会调用$controllerProvider的register方法注册一个ngAppDemoController.

同理:

constant()

给默认的$provider注册一个常量:

原理:在invokeQueue首部插入['$provide', 'constant', arguments]。

controller()

在$controllerProvider中注册一个控制器:

原理:在invokeQueue尾部插入['$controllerProvider', 'register', arguments]。

directive()

在$compileProvider中注册一个指令:

原理:在invokeQueue尾部插入['$compileProvider', 'directive', arguments]

factory()

生成一个服务工厂(隐式创建一个了服务提供商):

原理:在invokeQueue尾部插入['$provide', 'factory', arguments]

filter()

在$filterProvider中注册一个过滤器:

原理:在invokeQueue尾部插入['$filterProvider', 'register', arguments]

service()

注册一个服务(隐式创建了一个服务提供商):

原理:在invokeQueue尾部插入['$provide', 'service', arguments]

value()

注册一个变量(隐式创建了一个服务提供商):

原理:在invokeQueue尾部插入['$provide', 'value', arguments]

 

posted @ 2017-08-23 15:58  小时光  阅读(1995)  评论(0编辑  收藏  举报