Knockout框架:能否在两个ViewModel间传递值并实现交互?
两个Knockout ViewModel的交互实现方案
当然可以实现两个ViewModel之间的交互啦!你当前代码里赋值没生效的原因很简单:在startChat方法里你新建了一个chatModel实例,这个实例和你绑定到页面上的那个chatModel完全是两个不同的对象,所以修改它的username自然不会影响页面显示。
下面给你几种常用的解决方案,按需选择:
1. 直接传递ViewModel实例(最简单直接)
把页面上要绑定的chatModel实例提前创建好,然后传递给friendsOnlineModel,这样就能直接操作同一个实例了:
// 先创建要绑定到页面的chatModel实例 const chatVm = new chatModel(); // 修改friendsOnlineModel的参数,接收chatVm function friendsOnlineModel(data, mapping, chatVm) { const onlineFriends = ko.mapping.fromJS(data, mapping); onlineFriends.startChat = function() { // 直接操作传入的同一个chatVm实例 chatVm.username("olu"); }; onlineFriends.sending_message = ko.observable(""); return onlineFriends; } // 创建friendsOnlineModel时传入chatVm const friendsVm = friendsOnlineModel(yourData, yourMapping, chatVm); // 分别绑定到对应的div ko.applyBindings(friendsVm, document.getElementById('friendsDiv')); ko.applyBindings(chatVm, document.getElementById('chatDiv'));
2. 使用事件总线(解耦式交互)
如果不想让两个ViewModel直接依赖彼此,可以用事件发布/订阅的方式,通过一个中间事件总线传递消息:
// 实现一个简单的事件总线 const eventBus = { _events: {}, subscribe(eventName, handler) { if (!this._events[eventName]) this._events[eventName] = []; this._events[eventName].push(handler); }, publish(eventName, data) { if (this._events[eventName]) { this._events[eventName].forEach(handler => handler(data)); } } }; // 修改friendsOnlineModel,发布事件 function friendsOnlineModel(data, mapping) { const onlineFriends = ko.mapping.fromJS(data, mapping); onlineFriends.startChat = function() { // 发布更新用户名的事件 eventBus.publish("updateChatUsername", "olu"); }; onlineFriends.sending_message = ko.observable(""); return onlineFriends; } // 修改chatModel,订阅事件 function chatModel() { const chat = this; chat.username = ko.observable('kunle'); // 订阅更新用户名的事件 eventBus.subscribe("updateChatUsername", newUsername => { chat.username(newUsername); }); return chat; } // 正常实例化并绑定 const friendsVm = friendsOnlineModel(yourData, yourMapping); const chatVm = new chatModel(); ko.applyBindings(friendsVm, document.getElementById('friendsDiv')); ko.applyBindings(chatVm, document.getElementById('chatDiv'));
3. 父ViewModel托管共享状态(适合复杂场景)
如果你的页面逻辑更复杂,可以创建一个父ViewModel,让两个子ViewModel都挂载在父ViewModel上,通过父ViewModel来传递数据:
// 父ViewModel function ParentViewModel(data, mapping) { const parent = this; // 初始化两个子ViewModel parent.friendsVm = friendsOnlineModel(data, mapping); parent.chatVm = new chatModel(); // 给friendsVm的startChat方法赋值,让它能访问父级的chatVm parent.friendsVm.startChat = function() { parent.chatVm.username("olu"); }; } // 实例化父ViewModel并绑定到整个页面(或者父容器) const parentVm = new ParentViewModel(yourData, yourMapping); ko.applyBindings(parentVm); // 页面上的div绑定可以这样写: // <div data-bind="with: friendsVm">...</div> // <div data-bind="with: chatVm">...</div>
核心思路就是:必须操作同一个ViewModel实例,而不是每次都新建实例,这样数据更新才能同步到页面上。
内容的提问来源于stack exchange,提问作者appzone_oto
相关产品推荐
相关产品推荐

