什么是MVVM,我们应该使用它吗?

18

我一直在研究MVVM模式,特别是knockoutjs,但大多数时候它只会让我感到不适。我不想对保持结构、表示和显示分离的好处进行长篇大论,我只想问一个问题(以一个示例为例):两种方式之间有什么区别?

<button data-bind="click: someJavaScriptFunction">Something</button>

<button onclick="someJavaScriptFunction();">Something</button>

我们是否应该将这么多的行为控制放入标记中呢?尽管它干净并且极简,但它似乎违反了我曾听过的所有网络编程原则。

我错了吗?


2
我一直认为在一个文件中尽量不要使用多种语言。通常情况下,我会在页面构建完成后设置一个ID或类,并将函数绑定到它上面。 - dqhendricks
6
这里的问题似乎不是关于MVVM,而是关于Unobtrusive JavaScript的优缺点:http://en.wikipedia.org/wiki/Unobtrusive_JavaScript - Craig
@Craig 在标记中具有该数据绑定似乎不符合不显眼 JS 的精神,因此我不确定这是否真正与此有关。 - heisenberg
我不喜欢第一个例子:它有点假装不是代码,但实际上它确实是,那为什么不像第二个例子一样直接放实际的代码呢。虽然为了比较,你应该有第三个例子,其中事件根本没有嵌入到HTML中。我甚至不喜欢C# WPF中的MVVM,所以你不可能让我在JavaScript中使用它。 - nnnnnn
2个回答

13

以下是对你问题更直接的回答:

在第二个例子中,你指的是一个必须在全局作用域(即window对象的属性)中的函数。

在第一个例子中,你指的是当前视图模型的属性。

是的,这是微妙的区别,但它是一个重要的区别。如果你使用on-event属性,你只能引用存在于全局作用域中的东西。这意味着你必须把想要访问的所有内容放在全局作用域中,这会导致非常混乱的代码。

如果你使用声明式绑定,绑定的确切含义取决于上下文。

将HTML标记视为更偶然的事情可能有助于理解。实际上,你正在查看对视图模型进行结构化访问。将withforEach视为嵌套上下文,其他绑定视为其属性。声明式绑定与底层HTML之间的关系突然感觉更像使用XSLT。

这两个例子看起来非常相似。但是底层概念却大不相同,这也是数据绑定如此强大,而on-event属性如此讨厌的原因所在。

on-event属性被不赞成的原因不仅在于它们混合了逻辑和结构。而且它们是一种将任意JavaScript代码附加到HTML元素上的薄弱尝试,这妨碍了应用程序逻辑的正确封装。on-event属性是低级别的“钩子”,而绑定扩展了元素的行为。

话虽如此,使用声明式绑定也很可能做出人们使用on-event属性所做的同样可怕的事情。不同之处在于你可以用它们做什么其他事情。你不应该总是通过技术被滥用的方式来判断技术,我们都是成年人。


1
就我所知,除了单页应用程序(即:非常依赖JavaScript的Web应用程序)之外,绑定可能并不特别有用。 它们可以用于绑定诸如日期选择器之类的简单小部件,但是很难找到无法使用CSS选择器和jQuery轻松复制的普通网站的用例。 - Alan Plum
谢谢Alan。这个区别很有道理。+1 - nicholas
但是被调用的JavaScript的范围与您如何组织脚本有更多关系,而不是它是否应该存在于标记中。我可以很容易地做出类似的事情(使用常见的jQuery语法),例如onclick="$(this).data('myplugin').someFunction()"来使用onclick处理程序调用作用域函数。 - nicholas
我的观点仍然是标记用于数据显示和定义结构,脚本用于数据操作和行为,CSS用于样式。这三个应该尽可能松散耦合。我喜欢使用数据绑定(特别是knockout)将DOM从我的数据操作脚本中分离出来,让我自由地处理VM而不必担心数据如何显示。但我仍然不确定在标记中放置行为处理程序是否值得。 - nicholas

7
你在上面的代码示例中只使用了MVVM的其中一个部分,具体来说是View。使用Knockout(或任何其他MVVM库)的原因是为了轻松绑定视图到模型 - 视图模型 - 从而允许你停止编写大量的样板代码来返回视图中的值。
我看到很多奇怪的javascript / jquery代码,人们会像这样使用:
var ex = {
   some1: $('#textbox1').val(),
   some2: $('#textbox2').val()
};

这个问题在网络应用程序中广泛存在,到处都是,维护起来非常繁琐。我知道使用Knockout时,只要我的View更新了,我的View Model也会被更新。
并不是每个应用程序都需要它,也不应该仅仅因为它很“酷”就使用它。显然需要有使用它的理由,我上面的例子就是一个理由,我相信还有更多。

你所说的是数据绑定。这也是最初让我接触knockout的原因,但这并不是实现数据绑定的唯一方式。例如,有一个jQuery插件(http://ajaxian.com/archives/jquery-data-binding-templates-and-mobile-john-resig-at-fowa),可以非常轻松地实现数据绑定,而无需将该绑定逻辑嵌入到html中。 - nicholas
数据绑定,如DOM操作、模板化或依赖注入,似乎都不是任何特定模式的一部分,它们更像是技术或工具。 - nicholas
2
@nicholas 无论您是使用该库将HTML ID放入JavaScript中,还是使用Knockout将JavaScript字段名称放入HTML中,这种方式都有点相同,不是吗? MVVM的强大之处不在于数据绑定,而在于行为绑定,当您拥有视图状态属性而不仅仅是数据属性时,它可以更轻松地开发交互式屏幕。 但正如上面所述,它并非适用于每种用例,只是工具箱中的另一个工具。 - Paul Tyng
这是关于MVP的更多信息(其中MVVM是一种派生模式),作为Martin Fowler所介绍的设计模式: http://www.martinfowler.com/eaaDev/uiArchs.html - Paul Tyng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接