如何在使用AMD(require.js)时在Backbone.js中加载引导模型

Backbone.js文档build议以这种方式加载bootstrapped模型:

<script> var Accounts = new Backbone.Collection; Accounts.reset(<%= @accounts.to_json %>); var Projects = new Backbone.Collection; Projects.reset(<%= @projects.to_json(:collaborators => true) %>); </script> 

但是这是一个不能在AMD方法中使用的模式(使用require.js)

唯一可能的解决scheme是声明存储JSON数据的全局variables ,稍后在相关的初始化方法中使用这个variables。

有没有更好的方式来做到这一点(没有全局variables)?

这就是我们如何以不污染全局命名空间的方式引导数据。 相反,它只使用require.js。 它还可以帮助您根据模板中的variables提供初始应用程序configuration。

在您的呈现页面

 <script src="require.js"></script> <script> define('config', function() { return { bootstrappedAccounts: <%= @accounts.to_json %>, bootstrappedProjects: <%= @projects.to_json(:collaborators => true) %> }; }); </script> <script src="app.js"></script> 

globals.js

该文件检查configuration并使用返回的任何数据进行扩展

 define([ 'config', 'underscore' ], function(config) { var globals = { }; _.extend(globals, config); return globals; }); 

config.js

如果您希望能够加载应用程序,则无论您是否在页面中定义了config ,都需要此文件。

 define(function() { // empty array for cases where `config` is not defined in-page return {}; }); 

app.js

 require([ 'globals', 'underscore', 'backbone' ], function(globals) { if (globals.bootstrappedAccounts) { var accounts = new Backbone.Collection(globals.bootstrappedAccounts); } if (globals.bootstrappedProjects) { var projects = new Backbone.Collection(globals.bootstrappedProjects); } }); 

看起来你可以使用require.config()函数或“require”全局和“config”选项,以便通过特殊依赖“module”将数据传递给模块。 请参阅http://requirejs.org/docs/api.html#config-moduleconfig

通常需要将configuration信息传递给模块。 该configuration信息通常被称为应用程序的一部分,并且需要有一种方法将其传递给模块。 在RequireJS中,这是通过requirejs.config()的configuration选项完成的。 然后模块可以通过询问特定的依赖“module”并调用module.config()来读取这些信息。

所以,对于我们在顶级HTML页面中的引导模型:

 <script> var require = { config: { 'app': { bootstrappedAccounts: <%= @accounts.to_json %> bootstrappedProjects: <%= @projects.to_json(:collaborators => true) %> } } }; </script> <script src="scripts/require.js"></script> 

然后在应用程序模块(app.js)中,我们有:

 define(['module'], function (module) { var accounts = new Backbone.Collection( module.config().bootstrappedAccounts ); var bootstrappedProjects = new Backbone.Collection( module.config().bootstrappedProjects ); }); 

这里“模块”是为这些types的情况提供的特殊的依赖关系。

这是未经testing,但从文档看起来相当确定。

在RequireJS中,这是通过requirejs.config()的configuration选项完成的。 然后模块可以通过询问特定的依赖“module”并调用module.config()来读取这些信息。 例:

的index.html

 <script> var require = { config: { 'app': { 'api_key': '0123456789-abc' } } }; </script> <script src="js/libs/require.js" data-main="js/main"></script> 

main.js

 require( ['app'], function(App) { new App(); }); 

app.js

 define( ['module'], function(module) { var App = function() { console.log( 'API Key:', module.config().api_key ); }; return App; }); 

请注意,configuration对象的名称必须与模块的名称相匹配 。 在我的示例中,模块的名称是app ,所以configuration对象的名称也需要命名为app 。 在模块中,您需要将['module']作为依赖项,并调用module.config()[property name]来检索configuration数据。

阅读关于此的文档: http : //requirejs.org/docs/api.html#config-moduleconfig

这里的一些答案让我接近类似的问题,但没有什么钉牢。 特别是排名最高的和被接受的答案似乎给了我一个讨厌的竞争条件,有时虚拟对象会首先加载。 与优化器一起使用的时间也是100%。 它还使用明确的string名称模块,需要文档明确build议您不要这样做。

这是我的工作方式。 与Brave Dave类似,我使用configuration对象来捕获参数(在我的情况下从一个jsp页面)像这样

 <script type="text/javascript"> var require = { config: { options : { bootstrappedModels : ${models} } } } </script> 

特别要注意的是我的参数是在一个名为options的对象中。 这个名字不是可选的! 虽然文档没有提到这一点,但以下是如何加载你的configuration(requirejs 2.1.1中的第564行):

 config: function () { return (config.config && config.config[mod.map.id]) || {}; }, 

关键在于configuration对象上必须有属性,关键字为mod.map.id,parsing为“选项”。

从这里你可以像这样访问模型

 define(['module'], function(module){ console.log(module.config().bootstrappedModels); //... }); 

您可以在AMD模块的末尾添加一个Loopy函数,以检查init方法何时被定义(以便它可以在body之后填充,或者从include加载)。 这样模块就可以保证可用,并且在准备就绪时可以进行初始化。

 require(...,function (...) { //define models collections, etc.. var initme = function () { if(document.initThisModule) document.initThisModule(); else setTimeout(initme, 10); }(); }); 

我不太熟悉AMD方法,但是不使用全局variables,为什么不把JSON添加到dom中。

例如:

 var json = ..., $jsonContainer = $(json).wrap("<script id='json-container' type='text/javascript'>").appendTo($("body")); 

然后,在文档准备好的情况下,而不是骨干文档build议的embedded式脚本标记:

 $(function(){ MyCollection.reset($("#json-container").html()); ... }); 

如何做这样的事情:

 <script> define('Models', ['backbone'], function(Backbone) { var Models = { Accounts: new Backbone.Collection, Projects: new Backbone.Collection }; Models.Accounts.reset(<%= @accounts.to_json %>); Models.Projects.reset(<%= @projects.to_json(:collaborators => true) %>); return Models; }); </script> 

然后你就可以在其他模块中使用模型了:

 var models = require(['Models']); models.Accounts.doWhatYouNeed(); 

或这个:

 define(['any', 'dependencies', 'and', 'Models'], function(a, b, c, Models) { // Models will be available here }); 

像上面描述的那样,“数据模块”(或者configuration,或者你想要调用它的任何东西)可以被包含在一个已经生成的文件中(例如index.html),但是我觉得这很难看。

另一种方法是将其声明在自己的模块文件中,但是这需要在生产环境中额外往返服务器。 只要您想要构build和优化requirejs依赖关系,数据模块就不能被包含,因为它是在页面加载时dynamic生成的。

第三个选项可能是将其追加到您所服务的文件之一(例如,优化的requirejs文件),但我不知道如何/如果可以完成。

由@dlrust开发的工作,但它不能扩展参数,并通过代码从一个地方超过。 如果你尝试在渲染模板中做这样的事情:

 <script> define('config', function() { return { bootstrappedAccounts: <%= @accounts.to_json %>, bootstrappedProjects: <%= @projects.to_json(:collaborators => true) %> }; }); </script> 

并在另一个文件中添加一些数据

 <script> define('config', function() { return { goods: <%= some data %>, showcaseList: <%= some json or array %> }; }); </script> 

它被覆盖( 不扩展!!! )。 在configuration将只有最后申报的数据。

我的解决scheme:使用设置/获取数据的Backbone模型。

app.js

 define("App", [], function() { window.App = { // модели Model: {}, // коллекции Collection: {}, // виды View: {}, // роутеры Router: {}, // модальные окна Modal: {}, // UI компоненты UI: {} }; return window.App; }); 

global.js

 define(["App", "underscore", "backbone"], function(App, _, Backbone) { "use strict"; // модель глобальных данных App.Model.Global = Backbone.Model.extend({ defaults: {} }); return new App.Model.Global; }); 

index.php

 <!DOCTYPE html> <html> <head> <!--HEAD_START--> <script type="text/javascript" data-main="/app/init" src="/app/require/require.js"></script> <!--HEAD_END--> </head> <body> <div id="tm-inner-wrap"> <div id="loader"><i class="uk-icon-refresh uk-icon-spin"></i></div> <!--HEADER_START--> <?= $this->includeTpl('header_view'); ?> <!--HEADER_END--> <!--CONTENT_START--> <div>your html content data</div> <!--CONTENT_END--> <!--FOOTER_START--> <?= $this->includeTpl('footer_view');?> <!--FOOTER_END--> <script> require(["global"], function(Global) { Global.set("notifyList", <?=json_encode($this->notifyList);?>); }); </script> </div> </body> </html> 

另一个模板

someTemplate.php

 <div class="tm-inner-body"> <div class="uk-container uk-container-center"> // content data </div> </div> <script> require(["global", "module/index"], function(Global) { Global.set("goodList", <?=json_encode($this->goodList);?>); }); </script> 

index.js

 require(["App", "core", "jquery", "uikit!uikit-addons-min", "underscore", "backbone", "global", "module/good/goodView"], function(App, Core, $, UIkit, _, Backbone, Global, goodView) { "use strict"; // Global.get("notifyList"); its too able App.Collection.Good = new Backbone.Collection(Global.get("showcaseList")["items"]); // вид списка товаров App.View.GoodList = Backbone.View.extend({ // елемент el: ".tm-good-list", // init initialize: function() { this.collection = App.Collection.Good; // список товаров this.drawList(); }, // отрисовка списка drawList: function() { this.$el.empty(); this.collection.each(function(item, index) { this.$el.append(this.drawItem(item)); }, this); }, // отрисовка елемента drawItem: function(data) { var good = new goodView({model: data}); return good.render().el; } }); App.View.Index = Backbone.View.extend({ el: "body", // пользовательские события events: { // }, // init initialize: function() { var $this = this; if(Global.get("showcaseList")) new App.View.GoodList(); } }); new App.View.Index(); }); 

文件结构:

文件结构