javascript – Knockout JS在foreach绑定中调用ViewModel函数

让我们考虑使用类似的淘汰视图模型:
var data = [{ id: 1,name: "John Doe" },{ id: 2,name: ""},{ id: 3,name: "Peter Parker"}];

var viewmodel = {
    items: ko.observableArray(data)
};

viewmodel.showName = function (name) {
    console.log(this);
    return name && name.length > 0;
};

viewmodel.removePerson = function () {
    console.log(this); 
};

ko.applyBindings(viewmodel);

有了这个视图:

<ul data-bind="foreach: items">
    <li><span data-bind="text: id"></span>
         <span data-bind="visible: $root.showName(name)">Yes! show the name</span>
         <a href="#" data-bind="click: $root.removePerson">Remove</a>
    </li>
</ul>

你可以在这里看到它:http://jsfiddle.net/SmW35/8/

在这种情况下,当有人点击“删除链接,并且KO调用showName函数时,
函数内部的对象“this”,它是当前项目的对象,例如,如果我单击项目2中的“remove”,则“this”为{id:2,name:“”}
但是,当KO绑定“visible”并调用showName函数时,“this”对象不包含当前项,并且您必须将“name”传递给该函数(或者您可以使用$data).

所以,我有两个问题:

>有一种方法可以从View调用showName函数,而不传递名称或$data(与Remove链接相似的行为)
>如果没有,这样做有什么不对吗?我与一个认为不正确的同事进行了一次有趣的讨论,因为你是从View($root.showName(name))发送数据,然后这不是一个“纯粹的”MVVM模式.他建议创建一个自定义KO绑定来实现功能.在我看来是用坦克杀死苍蝇,但我很想知道是否有不同的方式,或者你也认为我没有用我的代码一个纯粹的MVVM模式.

解决方法

从某种意义上说,你的同事有一个观点.我不会亲自创建一个自定义绑定来处理这个问题(在一个持续的主观说明中,如果在视图和视图模型之间存在特殊的通信方式,则更有意图使用自定义绑定;有关何时使用它们的详细说明,请参阅 this post ).

另外,如果我们探索自定义绑定的选项,我想你可以做一些像textIfNotEmpty绑定处理程序,它将文本和可见结合在一起.另一方面,如果showName功能保持简单,您也可以选择:

<span data-bind="visible: !!name,text: name"></span>

无论如何,我更喜欢以下……

根本问题是IMO视图模型违反了单一责任原则:showName功能应该是表示项目的视图模型的责任.

var Item = function(data) {
    var self = this;

    self.id = data.id;

    self.name = ko.observable(data.name); 
    // or plain "self.name = data.name;" if you don't need 2way binding

    self.showName = ko.computed(function() { 
         return self.name() && self.name().length > 0;
    });
}

现在你可以像这样轻松绑定:

<ul data-bind="foreach: items">
    <li><span data-bind="text: id"></span>
         <span data-bind="visible: showName">Yes! show the name</span>
         <a href="#" data-bind="click: $root.removePerson">Remove</a>
    </li>
</ul>

这也允许您将removePerson重写为:

viewmodel.removePerson = function (person) {
    console.log(person); 
};

这确实需要你在构造可观察数组时做一些额外的工作,但它值得,因为它清楚地分离了所有关注点.它可以按照以下方式完成:

var viewmodel = {
    items: ko.observableArray(data.map(function(item) { return new Item(item); }))
};

有关上述演示,请参阅this fiddle.

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...