Backbone.js 状态管理/基于 url 片段的视图初始化
Posted
技术标签:
【中文标题】Backbone.js 状态管理/基于 url 片段的视图初始化【英文标题】:Backbone.js state management / view initialization based on url fragment 【发布时间】:2011-09-01 21:34:53 【问题描述】:我正在尝试使用 Backbone.js 跟踪此应用中的状态:
我有一个带有一组默认值的“ChartAppModel”:
ChartAppModel = Backbone.Model.extend(
defaults:
countries : [],
selectedCountries : [],
year : 1970,
,
initialize: function()
loadAbunchOfData();
checkStartState();
);
如果给定一个起始片段,这个默认状态应该被覆盖:
var startState = $.deparam.fragment(); //using Ben Alman's BBQ plugin
this.set(selectedCountries: startState.s, year: startState.y);
现在,例如 SidebarView 已准备好更新:
ChartAppViewSidebar = Backbone.View.extend(
initialize: function()
this.model.bind("change:selectedCountries", this.render);
,
render : function()
[... render new sidebar with check boxes ...]
,
问题是我在侧边栏上也有一个更新模型的事件处理程序:
events:
"change input[name=country]": "menuChangeHandler",
,
menuChangeHandler : function()
[... set selectedCountries on model ...]
,
所以会有一个反馈循环...... 然后,我还想要一种推动新状态的方法——所以我听取模型变化:
ChartAppModel = Backbone.Model.extend(
initialize: function()
this.bind("change", this.setState);
);
...很快这个状态管理器就会崩溃...
问题:
1) 我如何根据片段初始化我的视图(例如“应选中哪些复选框”)? (任何关于非典型“路线”的状态/开始状态最佳实践的提示都表示赞赏)
2) 如何避免我的视图在他们自己监听的模型上设置属性?
3) 如何根据模型的一部分推送新状态?
奖金:)
4) 您将如何布置所描述应用的代码?
谢谢!
【问题讨论】:
【参考方案1】:这是一个定义明确的问题!
关于什么是模型存在一个问题。我相信对于骨干世界中什么构成模型有一个定义,我不确定您的策略是否符合该定义。此外,您将状态存储在 url 和模型中。正如我将解释的那样,您可以将状态存储在 url 中。
如果我这样做,将有 2 个视图。一个用于您的应用程序控件,并嵌套在您的图表中:GraphView 和 AppView。模型将是您要绘制的数据,而不是界面的状态。
使用控制器启动应用程序视图并处理 url 中定义的任何界面状态。
有一个关于 Backbone 中的状态杠杆的问题。传统的 Web 应用程序使用链接/网址作为状态的主要杠杆,但现在一切都在改变。这是一种可能的策略:
Checkbox Change Event -> Update location fragment -> trigger route in controller -> update the view
Slider Change Event -> Update location fragment -> trigger route in controller -> update the view
这种策略的好处在于它可以处理 url 被传递或添加书签的情况
Url specified in address bar -> trigger route in controller -> update the view
我将尝试一个伪代码示例。为此,我将对数据做一些假设: 数据是随时间变化的狗数量(粒度为年份),其中滑块应该有一个下限和上限,并且体积数据太大而无法一次将其全部加载到客户端。
首先让我们看一下表示统计数据的模型。对于图表上的每个点,我们需要类似 人口:27000,年份:2003 让我们将其表示为
DogStatModel extends Backbone.Model ->
这些数据的集合将是
DogStatCollection extends Backbone.Collection ->
model: DogStatModel
query: null // query sent to server to limit results
url: function()
return "/dogStats?"+this.query
现在让我们看看控制器。在我提出的这个策略中,控制器名副其实。
AppController extends Backbone.Controller ->
dogStatCollection: null,
appView: null,
routes:
"/:query" : "showChart"
,
chart: function(query)
// 2dani, you described a nice way in your question
// but will be more complicated if selections are not mutually exclusive
// countries you could have as countries=sweden;france&fullscreen=true
queryMap = parse(query) //
if (!this.dogStatCollection) dogStatCollection = new DogStatCollection
dogStatCollection.query = queryMap.serverQuery
if (!this.appView)
appView = new AppView()
appView.collection = dogStatCollection
appView.fullScreen = queryMap.fullScreen
dogStatCollection.fetch(success:function()
appView.render()
)
【讨论】:
这是一个很好的答案——我开始重新考虑使用“路线”。但是假设我有一个带有 5 个参数的起始状态(url):year=1979、stacked=true、layout=fullscreen、selected=[Sweden、Finland]、zoom=2。基于这些参数,应加载数据,应计算 x/y 轴并应渲染视图等。使用路线的方法是什么?伪代码非常受欢迎 :=) 感谢@dani,不确定我的解释有多清楚。稍微有点相关的是,将滑块放在水平面下方可能会给用户带来一点混乱。我会用一些伪代码更新原始答案。【参考方案2】:2) 如何避免我的视图在模型上设置他们自己监听的属性?
你没有。您的模型应该对您尝试更新的任何属性进行验证,以便您的视图需要在属性设置失败或验证更改值的情况下进行侦听。
您的视图所做的是,尝试在模型上设置一个值,然后模型要么设置它,要么更改数据并设置它,要么拒绝它。您的视图需要相应更新。
3) 如何根据模型的一部分推送新状态?
// for each attribute
_.each(["attribute1", "attribute2", "attribute3", ...], _.bind(function(val)
// bind the change
// bind the setState with `this` and the `value` as the first parameter
this.bind("change:" + value, _.bind(this.setState, this, value));
, this));
【讨论】:
2) 是有道理的——所以从视图中设置模型属性然后在同一个属性上监听变化是没有问题的? 3)所以我基本上绑定到我想调用 setState 方法的每个模型属性?谢谢!附言。关于初始化/启动状态处理的任何输入? @dani 另外两个我没有意见,因为我只做过带骨干的玩具;)而且我不使用 jQuery BBQ 感谢您的帮助 :=)(而且那些 _.bind 不是玩具!)以上是关于Backbone.js 状态管理/基于 url 片段的视图初始化的主要内容,如果未能解决你的问题,请参考以下文章