KnockoutJS中跨ViewModel调用函数报错的正确实现方式求助
KnockoutJS跨ViewModel调用方法的正确姿势
首先得说你代码里的几个核心问题,这也是导致viewModelTwo.reloadData is not a function错误的根本原因:
- 你的立即执行函数(IIFE)没有执行(缺少末尾的
()),所以viewModelOne和viewModelTwo实际上只是函数本身,不是包含方法的实例对象; - 就算执行了IIFE,里面的
reloadData是私有函数,没有通过返回值暴露给外部,外部自然访问不到; - 定义顺序有问题,
viewModelOne先定义时,viewModelTwo还没完成赋值,直接引用会出问题。
下面给你两种可行的解决方案,根据你的场景选择:
方案一:直接引用(适合关联相对紧密的场景)
首先要确保ViewModel通过IIFE返回包含公共方法的对象,并且正确执行IIFE,同时调整定义顺序(让被引用的ViewModel先定义):
// 先定义viewModelTwo,因为viewModelOne要调用它的方法 var viewModelTwo = (function () { // 这里可以放私有变量/方法,外部访问不到 var privateVar = "something"; // 定义reloadData方法 function reloadData(url) { // 你的数据加载逻辑 console.log("viewModelTwo reload data with url:", url); } // 返回公共方法,暴露给外部 return { reloadData: reloadData }; })(); // 注意这里的(),执行IIFE得到实例 var viewModelOne = (function () { function saveSuccess() { // 现在可以正常调用viewModelTwo的reloadData了 viewModelTwo.reloadData(''); } function reloadData(url) { // 你的逻辑 } return { saveSuccess: saveSuccess, reloadData: reloadData }; })(); ko.applyBindings(viewModelOne, document.getElementById("modelOneContainer")); ko.applyBindings(viewModelTwo, document.getElementById("modelTwoContainer"));
方案二:发布订阅(事件总线,适合松散关联的场景)
既然你提到两个ViewModel是松散关联,这种方式更解耦,不需要直接引用对方,避免耦合:
我们可以自己实现一个简单的事件总线,让viewModelOne在保存成功时发布事件,viewModelTwo订阅这个事件并执行reloadData:
// 简单的事件总线实现 var eventBus = { subscribers: {}, // 订阅事件 subscribe: function(eventName, callback) { if (!this.subscribers[eventName]) { this.subscribers[eventName] = []; } this.subscribers[eventName].push(callback); }, // 发布事件 publish: function(eventName, data) { if (this.subscribers[eventName]) { this.subscribers[eventName].forEach(callback => callback(data)); } } }; var viewModelOne = (function () { function saveSuccess() { // 保存成功后发布事件 eventBus.publish('modelOneSaved', ''); } function reloadData(url) { // 你的逻辑 } return { saveSuccess: saveSuccess, reloadData: reloadData }; })(); var viewModelTwo = (function () { function reloadData(url) { // 你的数据加载逻辑 console.log("viewModelTwo reload data with url:", url); } // 订阅modelOneSaved事件,触发时执行reloadData eventBus.subscribe('modelOneSaved', reloadData); return { reloadData: reloadData }; })(); ko.applyBindings(viewModelOne, document.getElementById("modelOneContainer")); ko.applyBindings(viewModelTwo, document.getElementById("modelTwoContainer"));
这种方式的好处是,以后如果有其他ViewModel需要响应modelOne的保存成功事件,直接订阅即可,不需要修改viewModelOne的代码,完全解耦。
内容的提问来源于stack exchange,提问作者Rick
相关产品推荐
相关产品推荐

