模块化实际上我们并不陌生。例如,应用函数,应用类等进行封装。但是相对来说,以往的前端并没有很明显的模块化的概念。这样导致了有几个弊端。
1 分类不清晰。合作开发频繁冲突。
2 全局变量污染。
全局变量就是在所有作用域中都可见的变量。全局变量在很小的程序中可能会带来方便, 但随着程序越来越大,它很快变得难以处理。因为一个全局变量可以被程序的任何部分在任意时间改变,使得程序的行为被极大地复杂化。在程序中使用全局变量降 低了程序的可靠性。全局变量使在同一个程序中运行独立的子程序变得更难。如果某些全局变量的名称与子程序中的变量名称相同,那么它们将会相互冲突并可能导致程序无法运行,而且通常还使程序难以调试。
因此我们称之为全局变量污染。那么如果进行了模块化,将变量作用域定义为某个特定的模块内,就避免了类似的问题发生。
RequireJS 和 SeaJS
RequireJS 和 SeaJS 等等都是很不错的模块加载器两者区别如下:
1. 两者定位有差异。 RequireJS 想成为浏览器端的模块加载器,同时也想成为 Rhino / Node 等环境的模块加载器。SeaJS 则专注于 Web 浏览器端,同时通过 Node 扩展的方式可以很方便跑在 Node服务端。
2. 两者遵循的标准有差异。 RequireJS 遵循的是 AMD(异步模块定义)规范,SeaJS 遵循的是 CMD (通用模块定义)规范。规范的不同,导致了两者 API 的不同。SeaJS 更简洁优雅,更贴近 CommonJS Modules/1.1 和 Node Modules 规范。
3. 两者社区理念有差异。 RequireJS 在尝试让第三方类库修改自身来支持 RequireJS,目前只有少数社区采纳。SeaJS 不强推,而采用自主封装的方式来“海纳百川”,目前已有较成熟的封装策略。
4. 两者对调试等的支持有差异。 SeaJS 通过插件,可以实现 Fiddler 中自动映射的功能,还可以实现自动 combo 等功能,非常方便便捷。RequireJS 无这方面的支持。
5. 两者的插件机制有差异。 RequireJS 采取的是在源码中预留接口的形式,源码中留有为插件而写的代码。SeaJS 采取的插件机制则与 Node 的方式一致:开放自身,让插件开发者可直接访问或修改,从而非常灵活,可以实现各种类型的插件。
还有不少细节差异就不多说了。
在实际项目中我们选用了requireJs 进行了模块化管理。
接下来,就以一个最为简单的ionic实例来演示如何加入require.js实例。
接下来我们就以该示例为例,应用requireJs 进行模块化整理。
就先拿controllers.js开刀。首先我们看controllers.js的内容我们可以分为4个controller。分别为 DashCtrl.js ,ChatsCtrl.js,ChatDetailCtrl.js,AccountCtrl.js
然后在controllers文件夹下新建DashCtrl.js文件。
上图中该DashCtrl部分并没有任何方法。那么把它移到DashCtrl.js中,并让其符合require.js格式。则改为:
define([], function () {});
不过为了咱们的演示效果,我在这个方法里执行了一个赋值过程。
//dashCtrl.js content:
define([], function () {
'use strict';//以"严格模式"运行
function ctrl($scope) {
$scope.greet = "hello world";
}
return ctrl;
});
备注:这个controller就改好了。别的controller内容仍然不变,只是更改其符合为requirejs的格式即可。为了简化内容。咱们就不做这些功能了。我直接将其删除了。
先将原来的controllers.js移到controllers文件夹下面。
现在controller的目录为如下。
打开controllers.js ,需要将我们分开的几个使用require管理的controller 都汇总起来。其格式也是遵循requireJs
//controllers.js content:
define(function (require) {
'use strict';
var controllers = angular.module('starter.controllers', []);
//controllers.controller('controller名字',require(对应的文件地址));
controllers.controller('DashCtrl',require('controllers/dashCtrl'));
return controllers;
});
备注:实际应用中也需要对serverjs进行模块化。其模块化过程和controller的模块过程一模一样。还是为了简化演示的流程,我们在这里就不展开了。因为示例数据并没有应用services.js 咱们还是简单粗暴的将其删除。
添加文件:下载requireJs文件,将其放在了www-js 下面。
添加引用:在index.html文件中将对其的应用添加上。
同时设置其属性data-main=”js/main.js” 意为程序入口从main.js启动。
删除引用:因为我们已经设置了从main.js启动,所以在页面中将其原本对app.js controller.js services.js的引用删除
其内容如下:
// contents of main.js:
require.config({
baseUrl:'js',//基目录
deps: [
'bootstrap'//启动
]
});
其内容如下:
/*global define, require, console, cordova, navigator */
define(['app'], function (app) {
'use strict';
//方案1:如果不好理解下面的内容可以直接
// angular.bootstrap(document, [app.name]);
//这部分是方案1的内容
//方案2
angular.element(document).ready(function () {
console.log("bootstrap ready");
var startApp = function () {
angular.bootstrap(document, [app.name]);
}
var onDeviceReady = function () {
console.log("on deviceready");
angular.element().ready(function () {
startApp();
});
}
if (typeof cordova === 'undefined') {
startApp();
} else {
document.addEventListener("deviceready", onDeviceReady, false);
}
//这一部分是方案2的内容
});
});
同时我简化了路由。只配置了index页面。其内容如下。
define(['controllers/controllers'],
function () {
'use strict';
var app = angular.module('starter', ['ionic', 'starter.controllers'])
app.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
});
})
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state("index",{
url:"/index",
templateUrl:"index.html",
controller: 'DashCtrl'
})
$urlRouterProvider.otherwise('/index');
});
return app;
});
我们在页面上显示我们在DashCtrl方法中的赋值。
即在index页面 节点下添加
{{greet}}
应用requireJS进行模块化,也就是应用其将原本一个文件里的东西进行分离。在本文示例中,我们通过requireJS将原本在一个controllers文件里的东西进行了分离。其所有的实现都不改变。再实际应用中,还需要对servicesJs进行模块化等。总之,其实现思路是一致的。分离,注入,设置启动项。
此外,以下几篇博客也是关于ionic项目的相关讲解,推荐给大家。
ionic入门教程第三课-在项目中使用requirejs分离controller文件和server文件
ionic入门教程第四课-使用$controllerProvider按需加载controller