【问题标题】:Can event-handling be removed from KnockoutJS models and views?可以从 KnockoutJS 模型和视图中删除事件处理吗?
【发布时间】:2026-02-08 14:10:02
【问题描述】:

我使用 KnockoutJS 已经有一段时间了,主要用于中小型项目。但是,我现在正在处理一个非常大的项目,该项目对同一数据有许多不同的视图。例如,产品可以显示给客户,允许他们将产品添加到他们的购物车,也可以显示给管理员,允许他们编辑产品名称、价格和可用库存。我希望能够在这两种情况下使用相同的模型,但事实证明用 KnockoutJS 设计解决方案很困难。具体来说,我有两个问题:

我希望能够重复使用某些“查看”功能而无需重复自己。例如,在产品的客户视图和管理员视图中,单击产品缩略图会全屏显示产品图像。我可以将绑定信息移动到模型本身,而不是每个视图都包含相同的详细绑定代码(例如,两个视图中的 <img data-bind="event:{click:function codeToZoom(){}}"/>)。所以上面变成了<img data-bind="event:imageEvents()"/>。但是,执行上述操作会迫使我在模型中包含响应用户输入的代码,这违反了单一职责原则——例如,模型对业务逻辑负责,而不是响应用户输入。如果我决定让管理员单击缩略图以打开“上传新图像”对话框,那么我需要实现 imageEventsForAdministrator() 函数。

我问过人们如何处理上述问题,他们的回答是“编写两个不同的模型”。这听起来不错,直到您意识到产品具有大量嵌入式逻辑,并且编写两个不同的模型会迫使您复制该逻辑。所以:

根据 KnockoutJS,将业务逻辑响应事件/用户输入分开的推荐方法是什么?

【问题讨论】:

  • 你有没有考虑过使用继承来处理重复的逻辑?
  • 淘汰组件有一个视图模型,可以负责处理视图逻辑。业务逻辑可以封装在领域模型中。

标签: javascript html web-applications mvvm knockout.js


【解决方案1】:

您的帖子很有趣且易于理解......但对于 Stack Overflow 来说确实相当广泛。

不过,要回答您的一些更具体的子问题:

我希望能够重复使用某些“查看”功能而无需重复自己。

解决这个问题有两种典型的结构:

  • 使用templates 执行此操作。 Knockout 会将模板保留为“原型”视图,并根据需要实例化新实例(并清理)。
  • 如果愿意,可以将视图 html 动态加载为“部分视图”,并仅在需要时使用 the appropriate applyBindings overload 呈现这些位。

例如,[...] 单击产品缩略图会在两个视图中全屏显示产品图像 [...] <img data-bind="event:{click:function codeToZoom(){}}"/>

嗯,这里有几个选项。我发现,如果您愿意,实际上可以在理论上尽可能多地删除重复代码。首先,您通常可以这样做:

<img data-bind="event:{click: myHandler}"/>

您可以在视图模型上使用某种原型或经典继承,以确保 myHandler 只定义一次。

同样,如果您发现自己重复了 &lt;img... 位:使用 KO 模板。

继续:

这听起来不错,直到您意识到一个产品具有大量嵌入式逻辑,并且编写两个不同的模型会迫使您复制该逻辑。

在这种情况下,您可能违反了 SRP。您可能需要从视图模型中取出该逻辑 并将其放置在其他地方(例如,在控制器、DAL 等中)。但这个话题真的很广泛,我们的姊妹网站有an entire tag dedicated to it

最后,你问:

根据 KnockoutJS,将业务逻辑与响应事件/用户输入分开的推荐方法是什么?

KnockoutJS 不建议使用特定方法。

也就是说,KO 是一个 MVVM 库,因此它确实将您推向某个方向,但它并不会真正强迫您对此采取任何特定的方法。为常见的业务逻辑编写和构建基础架构和代码,想出一个好的继承策略或类似的东西,等等,这真的取决于你。

所以这取决于

作为脚注,如果您还没有,我建议您也阅读一些 AngularJS 教程。它具有 MVVM 样式绑定,但 IMO 对如何解决您面临的问题更加固执己见。 (这不是建议切换;只是建议在 KO 替代品中寻找灵感。)

【讨论】:

    最近更新 更多