【问题标题】:Complex KnockoutJS View Model复杂的 KnockoutJS 视图模型
【发布时间】:2015-10-23 16:26:11
【问题描述】:

我正在开始第二次尝试使用 KO 创建应用程序,所以虽然我觉得我对库的理解还过得去,但我使用它的执行仍然需要工作。我有一个关于不只代表一个逻辑实体的视图的复杂模型的问题。

给定一个复杂的或复合的视图模型,其中主视图模型的属性是对象本身:

var mainViewModel = function(data){
  var self=this;
  self.user = new UserModel();
  self.roles = new RolesCollectionModel();
}

function UserModel(data){
    var self=this;
    self.Name = ko.observable(data.name);
}

function RolesCollectionModel(data){
    var self=this;
    self.Items = ko.observableArray(data.items);
}

在我看来,KO 只识别第一级属性的绑定,没有“可观察到的冒泡”。因此,对于我来说要在子对象上使用数据绑定,看来我也必须将它们声明为可观察对象:

var correctViewModel = function(data){
    var self=this;
    self.SetUserModel= function(userData) {
            this.user = ko.observable(userData);
        }
    self.SetRoles = function (data) {
            this.roles = ko.observableArray(data);
        }
}

如果我想绑定 userModel 属性的名称,相应地在我的 html 中:

<input data-bind:'textInput:userModel().name'/>

那么我的问题是:

  1. 我的结论是否正确,即不会发生“可观察冒泡”,这是实现与对象图中多个级别的属性绑定的唯一方法?

  2. 假设我在 1 中是正确的,上面的语法对我来说很奇怪。 userModel 和 name 都是 observables,但为了使我的示例正常工作,我必须将对象引用为 userModel().name。我本来希望绑定到 userModel.name。这里很混乱,对吧?

** 我已对其进行了编辑以包含我将使用的设置器。这个想法是顶级模型将在 >1 次调用 API 后组合/绑定。我这样做是因为它在 OO 意义上更自然,但从这次对话中可以看出,我可以在 API 响应之后显式设置对象属性,例如:

var topModel = new CorrectViewModel();
$.ajax({...}).done(function(data){
    topModel.Users=(new UserModel(data));
})

我能问一下更惯用的风格是什么

【问题讨论】:

  • 主视图模型属性不需要是可观察的,不。 Here's a simplified example 以上内容。
  • 谢谢詹姆斯,我看到你的作品符合我的预期。我的没有,例如我必须使用我在这里展示的语法,这就是我发布这个问题的原因。我会进一步深入研究。
  • 我知道发生了什么。我无意中遗漏了一条关键信息。在我正在测试的模型中,我创建了 setter 方法,因为顶级模型不会一次全部实例化。子对象属性很可能会通过对 API 的单独调用来弹出:link
  • 在这种情况下,是的,它们需要是可观察的,以便淘汰赛知道它们何时被填充

标签: knockout.js


【解决方案1】:

回答 1:是的,你是对的,observables 不会“冒泡”。

回答 2:您必须使用该语法。

现在可以同时解释 1 和 2:observable 是一个函数,可以使用参数调用它来设置其值,或者使用参数来获取它。

当敲除找到一个绑定表达式时,它会检查它是否是可观察的:

  • 如果它是可观察的,淘汰赛“调用”它,以获得它的价值
  • 如果它不是可观察的,knout 会将代码评估为“普通 JavaScript”

让我们来看看几个案例:

// 1
var vm = { name: ko.observable(); };
// 2
var vm = { hidden: ko.observable(true); };
// 3
var userModel = ko.observable({
   name: ko.observable()
});

在所有这些情况下,如上所述,可观察对象是需要调用以获取或设置其值的函数。

  1. 最简单的情况是:text: name。 Knockout 检查 name 是一个 observable,所以 ko 调用它来获取它的值

  2. 稍微复杂一点:visible: !hidden()。在这种情况下,knockout 发现 !hidden() 它不是可观察的,并将其评估为“普通 JavaScript”。如果你写了visible: !hidden,knockout 还会检查它是否不是可观察的,所以它会将它评估为“普通 javascript”,结果总是false,因为hidden,没有括号来调用它,是function,这是一个 JavaScript truish 值,! 将 truish 值转换为 false

  3. 当有一个内部带有可观察属性的可观察对象时,您必须调用外部可观察对象来访问其中包含可观察对象的对象。在表达式userModel().name 中,括号调用userModel 以获取其中的对象,并且引用name 可观察对象。因此,当 Knockout 检查它是否是可观察的时,它会发现它是可观察的并对其进行评估。如果您指定了userModel.name,它将是yield undefined,因为userModel,没有用括号调用它,是一个没有name 属性的函数。

注意 1:knout 中有实用函数来发现某事物是否是可观察的:ko.isObservable(expr),并获取表达式的值,无论它是否是可观察的:ko.unwrap(expr) em>

注意 2A:可观察对象被实现为函数,因此当调用它们来设置它们的值时,它们可以通知它们已更改给所有订阅者。订阅是自动创建的。例如,当您指定绑定 text: userModel().name 时,必须设置文本的代码订阅了 name observable,这意味着无论何时调用 name,并且其值发生更改,它都会通知该代码,以便它可以更改文本。事实上你也可以像Aurelia那样做explicit subscriptions

注意 2B:一些语言,包括现代风格的 JavaScript 支持属性。一个属性被读取或写入就好像它是一个简单的变量,但它能够执行一些代码,而不是简单地设置或获取值。有一些 JavaScript 库使用了这个特性,这使得使用更简单的语法成为可能,没有括号

【讨论】:

    【解决方案2】:

    这是我通常如何构建深度绑定的示例,以便它有效地支持冒泡/多个子视图模型。

    假设您是特许经营经理,并且您管理着多个特许经营店/地点。

    var vm = {
        activate: activate,
        user: ko.observable(),
        currentFranchiseLocation: ko.observable(),
    };
    
    function activate() {
        vm.user(LoadYourUserHere().Result);
        vm.currentFranchiseLocation(LoadTheInitialLocation().result)
    }
    
    function changeLocation() {
        loadOtherLocation.done(function (data) {
            vm.currentFranchiseLocation(new FranchiseLocationVM(data));
        });
    }
    

    HTML 绑定

    <div data-bind="with: currentLocation">
        <h3 data-bind="text:Name"></h3>
        <div data-bind="text:numEmployees"></div>
    </div>
    

    这里的神奇之处在于with 关键字。它针对一个可观察的和变化的,重新绑定它的整个子树。同时,它将目标 observable 的内容解包并别名化为本地范围,因此您可以进行绑定,例如 text:Name,而不是 currentLocation().Name

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-31
      • 1970-01-01
      • 2015-07-19
      • 2014-08-23
      • 2015-10-31
      • 2012-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多