假设我有一个包含
的主视图两个元素都在同一个页面中,每个元素都有自己的VM,如下所示:
<div id='page'>
<div id='item'>
<span data-bind='text: item().name'></span>
<span data-bind='text: item().price'></span> EUR
<!-- What to bind on this click handler? -->
<button>Add</button>
</div>
<hr>
<div id='cart'>
You have 0 items in your cart.
</div>
</div>
的Javascript
function ItemVM() {
var self = this;
self.item = ko.observable({id: 1, name:'test', price: 3.99});
}
function CartVM() {
var self = this;
// Adds an item to cart.
self.add = function(item) {
// Business logic here
}
// And so on, other methods here.
self.remove = function(item) {}
self.checkout = function() {}
}
ko.applyBindings(new ItemVM(), document.getElementById('item'));
ko.applyBindings(new CartVM(), document.getElementById('cart'));
我有两个问题。
1)如何在“项目”上下文中使用在其他地方定义的点击处理程序?换句话说,如何使按钮使用CartVM.add()作为点击处理程序?
2)我在参考KO或MVVM本身时有什么问题吗?
答案 0 :(得分:1)
MVVM模式的想法是将视图绑定到单个viewModel。然后,您将拥有模型中描述的数据对象。
在你的情绪中,我倾向于喜欢构图。因此,如果我有一个由功能元素组成的视图,我倾向于组成这些单独元素的viewModel。
我觉得这总体来说更容易。容器VM可能会有一些实际上是单个页面的元素。如果有很多单独的viewModel是页面的一部分,那么可能很难理解。另一个问题是购物车与一个集装箱div相连。在购物车的情况下,这可能是可以接受的。在其他情况下,您的功能组件可能具有可能难以包含在一个div下的视图元素,因此很难像这样隔离viewModels。
我修改了你的设计:
注意我添加了一个要在itemVM中添加的调用,如图所示。
function ItemVM() {
this.add = function(data, e) {
viewModel.CartVM.add(data);
};
}
function VM() {
this.ItemVM = new ItemVM();
this.CartVM = new CartVM();
}
var viewModel = new VM();
ko.applyBinding(viewModel);
在这里说明这一点:http://jsfiddle.net/q8uWW/4/
HTH
答案 1 :(得分:0)
使用我的绑定约定库的示例,它使得使用多个视图模型变得容易。 https://github.com/AndersMalmgren/Knockout.BindingConventions
要在模型之间进行通信,您可以使用Event Aggregate模式,我在一个名为SignalR.EventAggregatorProxy的库中有一个,如果您没有使用SignalR,则可以提取eventaggregatorn部分。 https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/
我的约定库的想法是为每个视图模型使用模板绑定。像
<div id='page'>
<div id='item' data-name="item"></div>
<hr>
<div id='cart' data-name="cart"></div>
</div>
<script id="ItemView" type="text/html">
<span data-name='name'></span>
<span data-name='price'></span> EUR
<button data-name="add">Add</button>
</script>
<script id="CartView" type="text/html">
You have <span data-name="count"></span> items in your cart.
</script>