我理解在Knockout模型中处理DOM内容是一种不好的做法。但是,在模型中保存对元素的引用的正确模式是什么?
说我有一个菜单模型:
MenuModel = function()
{
var self = this;
self.buttons = [{ text: "set color" }, { text: "set border" }];
};
现在,此菜单代表一个DOM元素,菜单中的每个按钮都会操作所表示元素的DOM。
这是一个存储元素引用的正确模式吗?
MenuModel = function(el)
{
var self = this;
self.element = el;
self.buttons = [{ text: "set color" }, { text: "set border" }];
};
因此,当单击菜单按钮时,按钮的父模型(MenuModel)将保存对元素的引用。
我知道解决方案是为所表示的元素提供Knockout模型并更改该模型,以便元素根据模型更改而更改。但这对我来说不实用,此时我真的需要直接改变元素DOM。
答案 0 :(得分:3)
为什么要在JS中保存DOM元素的引用?我认为这是一种反模式。看看这个MVVM graphic from Wikipedia。很明显,您的MenuModel
并非真正的模型,而是viewModel
;它没有数据,只保存表示逻辑。模型将是您从后端获取的JSON / XML数据,并最终通过构造函数转换为命名对象实例。 viewModel(JS)和view(HTML)之间的流程通过data-binding
绑定。如果你坚持Knockout倡导者的模式,你应该保持这样简单:
<ul data-bind="foreach: buttons">
<li data-bind="text: text"></li>
</ul>
您只需向每个按钮对象添加一个动作属性,然后传递参数yourFunction(data, e)
即可操作您的视图,就像在下面的代码段中一样。如果您需要访问除视图层次结构中的元素之外的其他元素,您始终可以为其添加类/ ID,然后使用ko.dataFor(elem)
或ko.contextFor(elem)
引用其数据。
<ul data-bind="foreach: buttons">
<li data-bind="text: text, click: action"></li>
</ul>
对于性能/代码可读性,您可能不希望将事件绑定附加到每个元素(尤其是列表中)。在这种情况下,请参阅unobtrusive event handling上的Knockout部分或R.Niemeyer的插件Knockout delegated events等其他解决方案。
所以回答But what would be the correct pattern to hold a reference to an element in a model?
- 我会说,没有。在我编写的所有Knockout代码中,我无法想到需要这样的单个案例。如果这并不令人信服,请阅读What is separation of concerns?和loose coupling。