在不久的过去,这也是困扰我的事情。
为什么?
很简单,有两个原因。
第一个原因是我没有真正从对象的角度理解 JavaScript。对我来说,它一直是一种“脚本语言”,就是这样,我听到人们告诉我不是这样,但我(仍然)是一个 C# 人,所以我基本上忽略了所说的话,因为它看起来不像C# 对象。
一切都变了,当我开始使用 Type Script 时,TS 以 JS 输出的形式向我展示了对象 JS 的样子。
第二个原因是 JS 的灵活性,更重要的是淘汰赛。
我喜欢在 C# 代码中简单地更改我的 JSON 端点的想法,除了对我的 HTML 进行一些调整之外,实际上不必在前端进行任何更改。
如果我想向输出对象添加一个新字段,那么我可以,然后只需向表中添加一个新列,绑定正确的字段名称并完成工作。
太棒了。
确实如此,直到我开始被要求提供基于行的功能。它从简单的请求开始,例如能够删除行和执行内联编辑等操作。
这导致了许多奇怪的冒险,例如:
Knockout JS + Bootstrap + Icons + html binding
还有这个:
Synchronizing a button class with an option control using knockoutjs
但是请求变得更加陌生和复杂,我开始想出各种疯狂的遍历 DOM 的方法,从我所在的行开始,向上到父级并返回到我的兄弟级,然后拉出文本来自相邻元素和其他疯狂。
然后我看到了光
我开始与一个只知道和/或生活在 JS 领域的初级开发人员合作一个项目,他只是问了我一个问题。
“如果这一切都让你如此痛苦,那你为什么不为你的行创建一个视图模型呢?”
于是下面的代码就诞生了。
var DirectoryEntryViewModel = (function ()
{
function DirectoryEntryViewModel(inputRecord, parent)
{
this.Pkid = ko.observable(0);
this.Name = ko.observable('');
this.TelephoneNumber = ko.observable('');
this.myParent = parent;
ko.mapping.fromJS(inputRecord, {}, this);
}
DirectoryEntryViewModel.prototype.SomePublicFunction = function ()
{
// This is a function that will be available on every row in the array
// You can call public functions in the base VM using "myParent.parentFunc(blah)"
// you can pass this row to that function in the parent using "myParent.someFunc(this)"
// and the parent can simply do "this.array.pop(passedItem)" or simillar
}
return DirectoryEntryViewModel;
})();
var IndexViewModel = (function ()
{
function IndexViewModel(targetElement)
{
this.loadComplete = ko.observable(false);
this.phoneDirectory = ko.observableArray([]);
this.showAlert = ko.computed(function ()
{
if (!this.loadComplete())
return false;
if (this.phoneDirectory().length < 1)
{
return true;
}
return false;
}, this);
this.showTable = ko.computed(function ()
{
if (!this.loadComplete())
return false;
if (this.phoneDirectory().length > 0)
{
return true;
}
return false;
}, this);
ko.applyBindings(this, targetElement);
$.support.cors = true;
}
IndexViewModel.prototype.Load = function ()
{
var _this = this;
$.getJSON("/module3/directory", function (data)
{
if (data.length > 0)
{
_this.phoneDirectory(ko.utils.arrayMap(data, function (item)
{
return new DirectoryEntryViewModel(item, _this);
}));
} else
{
_this.phoneDirectory([]);
}
_this.loadComplete(true);
});
};
return IndexViewModel;
})();
window.onload = function ()
{
var pageView = document.getElementById('directoryList');
myIndexViewModel = new IndexViewModel(pageView);
myIndexViewModel.Load();
};
现在这不是最好的例子(我刚刚从我必须手头的项目中抽出它),但它确实有效。
是的,您必须确保如果您在 JSON 中将字段添加到后端,您还将其添加到行视图模型(您可以使用 RequireJS 或类似的加载),以及添加该列在需要的地方添加到您的表格/列表/其他标记。
但是为了多出一两行,您可以轻松地添加一个函数,然后在集合中的每一行都可以使用该函数。
而且,在 typescript 的注释上,上面的整个 JS 是由 TS 编译器从实现相同模式的 TS 源生成的。
我有很多东西以这种方式运行(在我的 github 页面上有几个例子 - http://github.com/shawty 你可以克隆),我运行的一些应用程序有完整的视图模型适应整个 UI 基于计算的 observable 中的单个简单更改,我有管理自己状态的行(包括直接与数据库对话),然后在操作成功后更新它们在父表中的状态。
希望这会给您带来更多思考。虽然您可能会在尝试扩展现有的 KO 课程的道路上挣扎,但老实说,您会发现上述模式更容易掌握。
我曾经尝试过和你一样的方法,但是当我的 JS 朋友指出为行创建一个 VM 并重新使用它是多么容易时,我很快就放弃了。
希望对你有帮助
肖蒂