【问题标题】:Revealing module pattern with Knockout-es5用 Knockout-es5 揭示模块模式
【发布时间】:2013-08-28 22:54:57
【问题描述】:

我正在尝试制作一个演示来使用knockout-es5 plugin 来简化使用显示模块模式的模型。 ViewModel1 是原始的 Knockout 模型,它工作正常。 ViewModel2 是尝试使用 knockout-es5 插件。遇到一些事情

  • 计算属性不起作用,因为未跟踪局部变量(例如 fullName1)。我可以使用 ko.defineProperty 但首先它与其他属性分开,其次必须使用 this.propertyName。
  • 可能出于同样的原因(例如,doSomething),成员函数所做的更改没有反映出来。再次使用 this.propertyName 有效,但违反了 RM 模式。

JS Fiddle

var NS = NS || {};

$(function () {

    NS.ViewModel1 = function (first, last) {
        var
            firstName = ko.observable(first),
            lastName = ko.observable(last),
            fullName = ko.computed(function () {
                return firstName() + " " + lastName();
            }),
            doSomething = function (n) {
                lastName(lastName() + " " + n);
            }
        ;

        return {
            firstName: firstName,
            lastName: lastName,
            fullName: fullName,
            doSomething: doSomething
        };
    };

    NS.ViewModel2 = function (first, last) {
        var
            firstName = first,
            lastName = last,
            fullName1 = ko.computed(function () {
                // Changed values are not reflected
                return firstName + " " + lastName;
            }),
            fullName2 = ko.computed(function () {
                // Should not work
                return this.firstName + " " + this.lastName;
            }),
            doSomething = function (n) {
                // Doesn't work
                lastName += " " + n;
                // Works
                // this.lastName += " " + n;
            }
        ;

        var retObj = {
            firstName: firstName,
            lastName: lastName,
            fullName1: fullName1,
            fullName2: fullName2,
            doSomething: doSomething
        };

        ko.track(retObj);
        ko.defineProperty(retObj, 'fullName3', function () {
            // Changed values are not reflected
            return firstName + " " + lastName;
        });
        ko.defineProperty(retObj, 'fullName4', function () {
            // Works
            return this.firstName + " " + this.lastName;
        });

        return retObj;
    };

    var vm1 = new NS.ViewModel1("John", "Doe");
    ko.applyBindings(vm1, document.getElementById("observableSection"));

    var vm2 = new NS.ViewModel2("Jane", "Doe");
    ko.applyBindings(vm2, document.getElementById("withoutObservableSection"));

    setTimeout(function () {
        vm1.firstName("John 1");
        vm2.firstName = "Jane 1";
    }, 2000);

    setTimeout(function () {
        vm1.doSomething(2);
        vm2.doSomething(2);
    }, 4000);
});

【问题讨论】:

    标签: knockout.js knockout-es5-plugin


    【解决方案1】:

    它不起作用,因为您直接从 github 链接了 JS。查看有效的更新小提琴:http://jsfiddle.net/tkirda/Wznkm/1/

    这不起作用的原因是因为 Github 指示内容类型是“text/plain”而不是“application/x-javascript”。

    Content-Type:text/plain; charset=utf-8
    Access-Control-Allow-Origin:https://render.github.com
    

    因此浏览器不执行此代码。我猜他们这样做是为了让人们停止从 GitHub 盗链文件。

    更新:如果您的 lastName 已更改,请添加 console.log ,您将看到它的新值。

            doSomething = function (n) {
                // Doesn't work
                lastName += " " + n;
                console.log(lastName);
                // Works
                // this.lastName += " " + n;
            }
    

    但是模型不使用它,因为当您将它们分配给 retObj 时,您只传递了值而不是引用。因为字符串是值类型。当您使用函数时,它们是引用类型。所以你只是更新了局部变量,但你的模型没有绑定到那个变量。

    var retObj = {
                firstName: firstName,
                lastName: lastName,
                fullName1: fullName1,
                fullName2: fullName2,
                doSomething: doSomething
            };                                 
    

    我希望这是有道理的。

    【讨论】:

    • 至少对我来说,这两个小提琴的工作方式完全相同。问题在于定义模型的两种方法之间。 observableSection 按预期工作,而 withoutObservableSection 则没有。在两次超时触发后,这两个部分都应显示“John 1 Doe 2”。我在本地也有相同的代码,两个 lob 都在本地提供,我得到相同的行为。
    • 感谢您的更新。我明白为什么它不起作用。有没有办法解决它,或者我不能同时使用这两者,即使用另一种模式或继续使用传统的属性语法。
    • 我建议尽可能简单。你真的需要保护那些作为闭包吗?
    • 简单是什么意思?已经是了。它是标准的显示模块模式。该项目已经在使用它,所以我希望使用新插件来简化未来的模型。我研究得越多,我意识到该插件旨在与上述博客文章和许多其他示例中定义模型的方式一起使用。没关系,我只是想确保我没有遗漏一些明显的东西。有时“不能这样做”的答案是正确的答案。
    • 我的意思是仅用作 ViewModel1 示例。
    【解决方案2】:

    我不确定您的问题是什么,但是它不适用于您尝试使用的模式。

    我喜欢 knout-es5 的想法,但它公开的当前 API 存在一些问题,如果你偏离他们的模式,这些问题真的会给你带来麻烦。

    另一个问题是,如果您将this.property 传递给其他视图模型,目标是其他视图模型能够订阅可观察对象或更新可观察对象,那么它显然不起作用。您将只是传递当前值。在这种情况下,您必须记住获取您的财产的实际可观察​​值。使用旧的淘汰赛,您知道当您访问该属性时您正在传递可观察对象本身。

    该项目还很年轻,因此希望这些 API 问题能够得到解决。但是现在,它需要开发者记住太多的东西才能把它做好。

    【讨论】:

    • 感谢您的回答。该项目已经在使用这种模式,所以我希望使用新插件来简化未来的模型。我研究得越多,我意识到该插件旨在与上述博客文章和许多其他示例中定义模型的方式一起使用。没关系,我只是想确保我没有遗漏一些明显的东西。有时“不能这样做”的答案是正确的答案。我会让它打开几天并接受。
    【解决方案3】:

    尽管我讨厌使用构造函数和损坏的“this”关键字,但显示模块模式几乎与 ES5 ko 插件完全不兼容(你可以让它在一个非常复杂和脆弱的方式,仅在简单的情况下)

    可跟踪的属性需要一个宿主对象(因此与您的私有变量不同)并且不能被复制(因为您会丢失新生成的 getter)

    所以选择两个弊端中较小的一个:p(对我来说这是 ES5 语法)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-12
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多