標籤:元素 release png one java 過濾 路徑 情況 port
最近因為要用到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依賴關係直接調用就行。
詳細內容請查看使用AngularAMD動態載入Controller和使用AngularAMD動態載入Service
安裝
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