【问题标题】:Four Backbone.js Model questions四个 Backbone.js 模型问题
【发布时间】:2011-09-02 09:38:39
【问题描述】:

我正在使用 Backbone.js 来跟踪可视化应用程序中的状态。

模型具有如下属性:

indicatorX : "income"
indicatorY : "emissions"
indicatorXScale : "lin"
indicatorYScale : "log"
year : 1980
layout : {leftPanel : {[...]}, rightPanel : {[...]}}  

1.在 Backbone.js 模型中处理“依赖属性”的好方法是什么?
例如,在更改 indicatorX 属性时,我还希望模型更新 indicatorXScale 属性。

2。如何处理 "lingering" 模型属性?示例:

模型包含这个:

indicatorX : "income"  
indicatorXScale : "log"

如果模型上只设置了indicatorX,那么scale应该设置为默认:

model.set( {indicatorX : "emissions"} )
if("indicatorX" in changedAttrs){
    indicatorXScale = dataSource[indicatorX].defaultScale
}

如果用户想要在“排放”指标的情况下覆盖默认比例“lin”怎么办?

model.set( {indicatorX : "emissions", indicatorXScale : log} )

由于模型属性indicatorXScale 已经设置为“log”,所以不记录更改的属性。在这种情况下,我如何确保未加载 defaultScale - 而是传递给模型的那个?

3。让模型使用额外的属性“action”来描述模型的变化是个好主意吗?
通过这种方式,控制器可以侦听一个属性,而不是为属性组合指定处理程序。这些是替代方案:

Alt 1. 控制器具有特定属性的处理程序:

this.model.bind("change:year", this.render);
this.model.bind("change:layout", this.updateLayout);  

Alt 2. 控制器具有模型更改处理程序,render() 确定要做什么:

this.model.bind("change", this.render);
render() {
   var changedAttributes = this.model.changedAttributes
   if (a,b && c in changedAttributes) x()
   if (a,d in changedAttributes) y()
}

Alt 3. 让模型描述属性变化的组合意味着什么:

this.model.bind("change:action", this.render);
render() {
   var changedAttributes = this.model.changedAttributes
   var action = this.model.get("action")
   if (action == gui_changeIndicator) x()
   if (action == gui_opacity) y()
}

4.在 Backbone.js 模型中使用对象作为属性时,有什么需要注意的陷阱吗?
例如,在我试图保留在模型中的布局状态上执行 isEqual 是否昂贵?另外,在设置模型时,对象是通过引用传递的,所以最好是一个新的对象来进行比较?

【问题讨论】:

    标签: javascript model-view-controller backbone.js


    【解决方案1】:

    1.在 Backbone.js 模型中处理“依赖属性”的好方法是什么?例如,在更改 indicatorX 属性时,我还希望模型更新 indicatorXScale 属性。

    恕我直言,扩展模型并绑定到更改事件中。例如:

    MyModel = Backbone.Model.extend({
        initialize: function() {
            this.bind('change:width', this.updateArea);
            this.bind('change:height', this.updateArea);
            this.updateArea();
        },
        updateArea: function () {
            this.area =  this.get('width') * this.get('height');
        }
    });
    
    var model = new MyModel({height: 10, width: 10});
    console.log(model.area); //100
    model.set({width: 15});
    console.log(model.area); //150
    

    这是非常基本的,但是每个键都会调用更改事件,并且作为一个整体“更改”..因此您可以绑定到某些更改并根据需要进行更新。如果它是一个带有大量间歇性更新的键的大型模型,那么这绝对是要走的路。如果只是这两个键.. 好吧.. 你可能只绑定一次常规的 ol' 更改事件。

    2.如何处理“延迟”模型属性?

    重写 set 方法并添加一些您自己的代码。示例:

    MyModel = Backbone.Model.extend({
        constructor: function (obj) {
            this.touched = {}; //Set before the prototype constructor for anything being set
            Backbone.Model.prototype.constructor.call(this, obj);
            //set after for only things that the program has updated.
            return this;
        },
        set: function(attributes, options) {
            if(attributes.keyIWantToListenFor !== undefined && !this.touched.keyIWantToListenFor) {
                console.log("keyIWantToListenFor was set, let's fire off the right methods");
                this.touched.keyIWantToListenFor = true;
            }
            Backbone.Model.prototype.set.call(this, attributes, options);
            return this;
        }
    });
    
    var model = new MyModel({height: 10, width: 10});
    model.set({keyIWantToListenFor: 15});
    

    这在模型上保持绝对的“是否已设置密钥”。它可能不够具体,无法满足您的需求,但它确实有效。所以请随意使用和破解它。

    3.让模型使用额外的属性“action”来描述模型的变化是不是一个好主意?

    Backbone 人员的设置方式是,如您所知,change:key 专门针对某个键上的更改事件。依靠 change:action 你有点像在你的代码中添加'gotcha!'。我看不出其他两种方法比第一种更好,特别是考虑到现在您将逻辑投入到事件侦听器中以确定要触发的内容.. 而不是直接将该代码附加到适当的侦听器。如果有选择,我会坚持第一个 - 很明显“此密钥已更新,因此我们将执行 X”。不是“某些东西已经更新,所以让我们去弄清楚它是什么!”并且可能需要经过十几个 if 语句或开关。

    4.在 Backbone.js 模型中使用对象作为属性时有什么需要注意的陷阱吗?

    好吧,isEqual 执行深度比较..所以你冒着执行所有比较代码的风险加上递归的风险。所以,是的,如果你多次这样做,那肯定是一个陷阱。

    引用的对象肯定是个问题——我在墙上有一个漂亮的小洞,我已经把头穿过了几次想知道为什么在一个完全不相关的地方发生了变化..哦等等.. 为了解决这个问题,您可以重写 get 方法,在它返回对象的情况下,返回类似 $.extend(true, {}, this.get(key));

    此外,您并不真正知道基于普通 Backbone 的对象到底发生了什么变化。因此,如果您在更改上做了很多“事情”(重建视图等),您可能会遇到性能问题,即使您所做的只是向该对象添加另一个属性并且它不是用于任何上述更改。 (即 set({layout: layoutObj}) vs set({layoutPageTitle: 'blah'}) 可能只更新标题..而不是导致整个视图重新加载)。

    否则,至少在我正在开发的应用程序中,骨干中的对象没有真正的问题。它们同步得相当好,它肯定比 .get('layout.leftPanel[0]') 更好,并且有一些神奇的翻译来完成这项工作。请注意参考部分。

    希望至少有一点帮助!

    【讨论】:

    • @Stephen:“希望至少有一点帮助!”不,这很有帮助:) 感谢您提供真正出色的答案。关于我的第三个问题,我仍在考虑使用额外的属性“动作”......?能够说“属性变化的某些组合”等于“一个动作”会很方便。这不是让每个控制器绑定到许多属性或让每个控制器执行“高级逻辑”来查看哪些属性发生了变化并调用必要的函数。相反,模型执行此逻辑 ONCE 并且控制器可以监听一个动作 - 例如 scaleChange、layoutChange 等。
    猜你喜欢
    • 2011-09-17
    • 2012-01-19
    • 1970-01-01
    • 1970-01-01
    • 2012-02-12
    • 1970-01-01
    • 2012-04-07
    • 2012-02-15
    • 2014-08-11
    相关资源
    最近更新 更多