【问题标题】:scoping in Durandal viewmodelDurandal 视图模型中的范围界定
【发布时间】:2013-10-22 23:30:19
【问题描述】:

在我的一个视图模型中,我有一个函数Control,它稍后会创建一个对象以绑定到视图:

(代码只是复制我的视图模型,因此它可能不完整或包含一些错误。如果您需要更多详细信息,请在下面的评论中提问。由于示例涉及 durandaljs 框架,我无法提供 JsFiddle。)

function Control ( value ) {
    var self = this;
    self.param = value;
    self.param1 = ko.observable(value.text());
    self.param2 = ko.computed(function() {
        read: function(){
            return getString(self.param.text()).StringValue();
        },
        write: function(newValue){
            stringsArray.push(
                {StringID: ko.observable(-1), StringValue: ko.observable(newValue)});
            self.param.text(-1);
        },
        owner: self
    });
    self.param3 = ko.computed(function() {
        return self.param2() + ' something_else';
    });
    self.param1.subscribe(function( newValue ) {
        if ( newValue ) {
            self.param3(newValue + 'text');
        }
    });

}

var controls = ko.observableArray([
    new Control({id: 1, text: ko.observable(2)}),
    new Control({id: 2, text: ko.observable(4)}),
    new Control({id: 2, text: ko.observable(1)})
]);

var stringsArray = ko.observableArray([
    {StringID: ko.observable(1), StringValue: ko.observable('aaa')},
    {StringID: ko.observable(2), StringValue: ko.observable('bbb')}
    {StringID: ko.observable(3), StringValue: ko.observable('ccc')}
    {StringID: ko.observable(4), StringValue: ko.observable('ddd')}
    {StringID: ko.observable(5), StringValue: ko.observable('eee')}
    {StringID: ko.observable(6), StringValue: ko.observable('fff')}
]); // data retrieved from the database

var deactivate = function() {
    controls.removeAll();
    stringsArray.removeAll();
};

var vm = {
    deactivate: deactivate,
    controls: controls,
    stringsArray: stringsArray
};
return vm;

function getString ( stringID ) {
    for ( var i = 0; i < stringsArray().length; i++ ) {
        if ( stringsArray()[i].StringID() === stringID ) {
            return stringsArray()[i];
        }
    }
    return undefined;
}

我的问题是从函数创建的对象是全局范围的,因此当我停用视图模型时,它们仍然存在于内存中。

我应该如何重写function Control(value),以便它创建的对象将具有视图模型范围。只有当视图模型处于活动状态时它们才会存在,当我在 deactivate 方法中将它们从 observableArray 中删除时丢弃它们?

【问题讨论】:

  • 检查是否开启了 cacheViews: true。虚拟机返回一个单例,因此使用 cacheViews: true 视图将永远不会被删除。
  • 我尝试添加cacheViews: false,但它仍然是相同的行为。问题是在function Control() 中创建的对象的范围。现在创建的对象的范围是全局的。我不知道如何重写函数,所以对象的范围只能是视图模型。
  • 你能复制下面的例子并重现这种行为吗?
  • 很奇怪。我在函数 Control 的开头放了一个console.log(this),它打印了一个对象Control {}。我也把它放在函数的末尾,它返回了全局对象Window {...}
  • dfiddle.github.io/dFiddle-2.0/#extras/scope (github.com/dFiddle/dFiddle-2.0/blob/gh-pages/app/extras/scope/…) 正在使用上面的原始代码,但我没有看到任何关于 global 的内容。你能重现它吗?

标签: javascript mvvm durandal


【解决方案1】:

有趣的例子,但我不确定上面的代码是否真正反映了你在做什么,或者它是否是一个复制/粘贴问题。

为了调试它,我在http://dfiddle.github.io/dFiddle-2.0/#extras/scope 提出了一个 dFiddle。随意 fork 和修改。

当前,当您离开视图时,Durandal 的实时循环事件deactivate 被触发,这将触发来自stringArraycontrolsremoveAll 条目,但当然至少在视图模型的情况下将淘汰的 observableArrays 留在内存中返回一个单例并且 cacheViews 设置为 true。

我很可能会将 vm 转换为构造函数,然后将控件移到它自己的模块中,但当然不知道确切的要求,这只是一种直觉。

以下内容应该可以帮助您入门:

查看模型

define(['durandal/system', 'jquery', 'knockout', './control'], function( system, $, ko, Control ) {
    "use strict";

    var vm = function() {
        this.controls = ko.observableArray([
            new Control('value1'),
            new Control('value2'),
            new Control('value2')
        ]);
    };

    vm.prototype.deactivate = function() {
        this.controls.removeAll();
    };

    return vm;
});

控制模块

define(['knockout'], function(  ko ) {
    "use strict";

    function Control ( value ) {
        this.param = value;
        this.param1 = ko.observable(value.text);
        this.param2 = ko.computed(function() {
            //translate self.param.StringID with data from another
            //an observableArray containing data retrieved from the server
            //return getString(this.param.StringID()).StringValue();
            return 'Computed' + this.param.id;
        // ko.computed takes a context parameter
        }, this);
        this.param3 = ko.computed(function() {
            return this.param2() + 'something_else';
        }, this);
        this.param1.subscribe(function( newValue ) {
            if ( newValue ) {
                this.param3(newValue + 'text');
            }
        });
    }

    var stringsArray = ko.observableArray([]); // data retrieved from the database

    return Control;

    function getString ( stringID ) {
        for ( var i = 0; i < stringsArray().length; i++ ) {
            if ( stringsArray()[i].StringID === stringID ) {
                return stringsArray()[i];
            }
        }
        return undefined;
    }

});

http://dfiddle.github.io/dFiddle-2.0/#extras/scope/ctor提供实时版本

【讨论】:

    【解决方案2】:

    显然我的问题是对象包含的ko.computed。当我停用视图模型时,计算并没有删除,因为它们所依赖的一些外部数据仍在内存中。

    我在这篇文章中发现了它:https://groups.google.com/d/msg/knockoutjs/4HV_PgcBNXA/ozoyXlygJHwJ

    在停用功能中手动处理ko.computed后,问题消失了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-17
      • 1970-01-01
      • 1970-01-01
      • 2014-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-16
      相关资源
      最近更新 更多