參考:
ionic入門教程第十六課-在微信中使用ionic的解決方案(按需加載加強版)作者有一系列的ionic教程,很不錯!
自己的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]