Marionette.Module
Marionette.Module
Marionette 模块允许你创建模块化封装的逻辑.他们可以用户将大程序分离为多个文件,构建你应用独立的组件.
文档目录
基本使用
模块定义
回调函数定义
对象字面量定义
模块类
定义子模块
开始和停止模块
开始模块
开始事件
阻止模块的Auto-Start
使用Parent开始子模块
停止模块
停止事件
模块初始器(弃用)
模块终止器(弃用)
基本使用
模块直接从Application对象定义,创建模块需要给它给它个名字.
var MyApp = new Marionette.Application(); // Creates a new module named "MyModule" var myModule = MyApp.module("MyModule"); myModule === MyApp.MyModule; // => true
模块一旦创建后不能重载.用相同参数module的后续调用不会创建新的模块,而是返回已经创建的模块.
var MyApp = new Marionette.Application(); // Instantiates a new Marionette.Module var myModule = MyApp.module("MyModule"); // Returns the module you just created var theSameModule = MyApp.module("MyModule");
模块定义
当你实例化时你可以为你的模块提供定义.定义也可以是回调函数或对象字面量.
回调函数定义
回调函数定义将在调用module方法时立即唤醒.
接收6个参数,按顺序为:
模块自己
应用对象
Backbone
Marionette
jQuery
Underscore
任意自定义的参数
在回调中你可以直接向你的模块附加公有和私有函数和数据.
MyApp.module("MyModule", function(MyModule, MyApp, Backbone, Marionette, $, _){ // The context of the function is also the module itself this === MyModule; // => true // Private Data And Functions // -------------------------- var myData = "this is private data"; var myFunction = function(){ console.log(myData); } // Public Data And Functions // ------------------------- MyModule.someData = "public data"; MyModule.someFunction = function(){ console.log(MyModule.someData); } }); console.log(MyApp.MyModule.someData); //=> public data MyApp.MyModule.someFunction(); //=> public data
额外的参数
你能在定义函数中提供额外参数,让你可以引用想要在你的模块域内的第三方库和别的资源.
在module调用自己的定义时传递传递参数.
MyApp.module("MyModule", function(MyModule, MyApp, Backbone, Marionette, $, _, Lib1, Lib2, LibEtc){ // Lib1 === LibraryNumber1; // Lib2 === LibraryNumber2; // LibEtc === LibraryNumberEtc; }, LibraryNumber1, LibraryNumber2, LibraryNumberEtc);
模块分开定义
有时模块定义很长.你可以对模块函数的连续调用来分开定义.
这可用于跨多个文件来定义你的模块.
MyApp.module("MyModule", function(MyModule){ MyModule.definition1 = true; }); // The following could be in a separate file MyApp.module("MyModule", function(MyModule){ MyModule.definition2 = true; }); MyApp.MyModule.definition1; //=> true MyApp.MyModule.definition2; //=> true
对象字面量定义
模块的字面量对象定义使得比回调方法更灵活.比如使你为你的模块指定自定义类.
通过字面量对象定义可通过define属性来设置定义函数.
MyApp.module("MyModule", { define: function(MyModule, MyApp, Backbone, Marionette, $, _) { // Define your module here } });
指定自定义模块类
对象字面量定义的一个好处是指定自定义模块类.你可使用扩展函数创建一个新类.
当moduleClass省略时Marionette将默认实例化一个新的Marionette.Module.
var CustomModule = Marionette.Module.extend({ // Custom module properties }); MyApp.module("Foo", { moduleClass: CustomModule, define: function() {} // You can still use the definition function on custom modules });
初始化函数
模块一个初始化函数,当Module 唤醒时立即调用.你可以将initialize函数看做构造函数的扩展.
初始化函数仅当使用模块的字面量对象定义时有效.
初始化函数和构造函数传递相同参数.
模块名称
应用
模块自己的对象字面量定义(允许你向模块传递任意值)
MyApp.module("Foo", { initialize: function( moduleName, app, options ) { console.log( options.someVar ); // Logs 'someString' }, someVar: 'someString' });
初始化函数和define函数不同.主要区别是初始化函数是在原型链上,而define不是.也就是说initialize可以被继承.
var CustomModule = Marionette.Module.extend({ define: function() {}, // This is not inherited and will never be called initialize: function() {} // This, on the other hand, will be inherited });
模型类
模型类可以选择性的用于定义模式
Module的extend函数和其他Backbone和Marionette的extend方法相同.允许模型生命周期事件比如onStart和onStop直接调用.
var FooModule = Marionette.Module.extend({ startWithParent: false, initialize: function(options, moduleName, app) { }, onStart: function(options) { }, onStop: function(options) { }, }); MyApp.module("Foo", FooModule);
若模型的所有功能在它的类中定义了,类可以直接传递.MyApp.module("Foo",FooModule)
定义子模型
子模型可以通过传递逗点分割的模块列表来在一次调用中定义.
MyApp.module("Parent.Child.GrandChild"); MyApp.Parent; // => a valid module object MyApp.Parent.Child; // => a valid module object MyApp.Parent.Child.GrandChild; // => a valid module object
当使用逗点来定义子模块时,父模块可以不存在,他们会自动为你创建.如果父模块已经存在实例化,那个实例将被使用.
获取模块
虽然模块直接附加到Application实例上,我们不建议这种方式获取,而是使用.module()函数来获取.
让我们看看两种获取MyModule.Submodule模块的方式.
// Not recommended var myModule = App.MyModule.Submodule; // Recommended var MyModule = App.module('MyModule.Submodule');
启动和停止模块
模块可以依赖应用和其他模块来启动和停止。这让它们可以异步加载,也可以在不需要时停止。
这让单元测试也容易,因为你可以在测试中仅仅启动你需要测试的模块。
启动模块
模块默认开启随着父应用同时开启。用于启动停止的模块有一个.start函数.或者模块可以配置依赖于父级的启动而启动.
例子中,模块随着父级应用对象的start方法调用而展示自动也启动的行为.
MyApp = new Marionette.Application(); MyApp.module("Foo", function(){ // module code goes here }); MyApp.start();
注意MyApp.start()调用后加载的模块将立即启动.
启动事件
当模块启动时,'before:start'事件将优先于其它运行的任何初始化器首先被触发.'start'事件然后在它们之后触发.
var mod = MyApp.module("MyMod"); mod.on("before:start", function(){ // do stuff before the module is started }); mod.on("start", function(){ // do stuff after the module has been started });
启动事件传递数据
.start接受单个options参数,这个参数同时传递到相关方法(onStart和onBeforeStart)上.
var mod = MyApp.module("MyMod"); mod.on("before:start", function(options){ // do stuff before the module is started }); mod.on("start", function(options){ // do stuff after the module has been started }); var options = { // any data }; mod.start(options);
阻止模块的Auto-Start
默认模块随着应用启动而启动.如果你想要手动启动模块,你可以通过startWithParent属性改变此行为.
var fooModule = MyApp.module("Foo", function(){ // prevent starting with parent this.startWithParent = false; // ... module code goes here }); // start the app without starting the module MyApp.start(); // later, start the module fooModule.start();
模块的字面量对象定义来定义这种行为.
var fooModule = MyApp.module("Foo", { startWithParent: false });
当将模块跨文件分割时,建议将startWithParent设为false.
随着父级开启子模块
子模块默认随着父模块而启动.子模块按照深层优先的顺序启动.也就是说,Foo.Bar.Baz这样的层次首先启动Baz,然后Bar,最后Foo.
MyApp.module("Foo", function(){...}); MyApp.module("Foo.Bar", function(){...}); MyApp.start();
例子中,'Foo.Bar'模块将随着MyApp.start()方法调用启动,因为'Foo'默认随着app而启动.
子模块可以设置startWithParent为false来重载此行为.这阻止通过父级的start方法调用而启动.
现在模块'Foo'将启动,但是子模块'Foo.Bar'将不会启动.
MyApp.module("Foo", function(){...}); MyApp.module("Foo.Bar", function(){ this.startWithParent = false; }) MyApp.start();
通过上述配置子模块将使用手动启动.
MyApp.module("Foo.Bar").start();
停止模块
模块可以停止或关闭,在模块不需要时来清除内存和资源.像启动模块那样,停止也是按照深度优先的层次顺序.也就是说,'Foo.Bar.Baz'的层次模块将首先停止Baz,然后Bar,最后Foo.
停止模块和孩子模块,调用模块的stop方法
MyApp.module("Foo").stop();
模块不会被应用自动停止.如果你想要停止比须调用自己的stop方法,或在父级模块上调用stop方法.当你停止任何父级模块时,所有的孩子模块也会被停止.
MyApp.module("Foo.Bar.Baz"); MyApp.module("Foo").stop();
stop方法的调用会让Bar和Baz模块同时停止,因为它们是Foo的子模块.关于定义子模块的详情,请看'定义子模块'章节.
停止事件
当停止模块时,'before:stop'事件在任何终止器前首先触发 .'stop'事件将在它们运行后触发.
var mod = MyApp.module("MyMod"); mod.on("before:stop", function(){ // do stuff before the module is stopped }); mod.on("stop", function(){ // do stuff after the module has been stopped });
模块Initializers
警告:弃用
这个特性已经弃用,计划在Marionette 版本3中移除.
而不是使用Initializer,你应该使用事件来管理启动过程逻辑.start事件是Initializer的理想代替品.
如果你依赖Initializer的延迟特性,你应该使用Promise来代替.这看起来像下面这样:
doAsyncThings().then(myModule.start);
模块,可以像Application对象那样配置成拥有initializer.就像Application的initializer这样,模块的initializer在模块启动时运行.而且,没有initializer数量的限制.
initializer可以通过模块的定义函数来添加.
MyApp.module("Foo", function(Foo){ Foo.addInitializer(function(){ // Do things once the module has started }); Foo.addInitializer(function(){ // You can have more than one initializer }); });
模块Finalizers
警告:弃用
这个特性已经弃用,计划在Marionette 版本3 中移除,代替使用Finalizer,你应该使用事件来管理停止逻辑.停止事件是Finalizer的理想替代.
如果你在你的app中依赖Finalizer的延迟特性,你应该使用Promise.看起来像下面这样:
doAsyncThings().then(myModule.stop);
模块有和initializer工作相反的finalizer:当模块通过stop方法停止时被调用.
你可以有你需要的多个finalizer
MyApp.module("Foo", function(Foo){ Foo.addFinalizer(function(){ // Tear down, shut down and clean up the module in here }); Foo.addFinalizer(function(){ // Do more things }); });