Open kuitos opened 8 years ago
学习前端架构!
视图通过绑定,或者调用 view-model 上的方法来获取数据。 A view gets data from its view model through bindings, or invoking methods on the view model.
view可以通过数据绑定来获取数据,也可以触发view model上的方法。 个人认为这段话主要是讲view能做什么,而不是怎样获取数据。
"MVVM 模式的设计动机" 这一部分的内容我觉得第 2,3 点是比较符合微软的动机的,也应该是最重要的出发点,从这篇古早的发布公告(https://docs.microsoft.com/zh-cn/archive/blogs/johngossman/introduction-to-modelviewviewmodel-pattern-for-building-wpf-apps) 可以看出来, mvvm 指导思想其实相当简单的:
虽然 Blend 最终市场效果不是太好,抛开一些技术细节的原因,整个 windows 平台的大环境可能也更重要。
最近在搞云凤蝶的一些设计的时候各种挖坟,发现巨硬的各种技术框架其实都相当超前了,比如你这篇翻译里面也提到的不管是 wpf 的 DataContext 还是 angularjs 的 scope 的设计,都是我在处理云凤蝶数据绑定时候遇到的种种问题的解法... 当然我们在低代码场景不会搞得像 angularjs 这么复杂
[译注] MVVM 模式
MVVM 模式跟 Silverlight 这类 XAML 应用平台是天生合拍的。这是因为 MVVM 模式利用了Silverlight 的一些特殊能力,比如说 数据绑定,命令,行为等。MVVM 跟其他一些将表现及UI布局 与展示层逻辑的职责进行分离的模式很相似;如果你对 MVC 模式熟悉的话,你会发现它与 MVVM 之间存在很多相似的概念。
诸如 Windows Forms,WPF,Silverlight 以及 Windows Phone 这类开发技术都提供了一个默认的体验,那就是它可以让开发者从工具箱中拖拽控件到设计面板,然后在代码文件中编写一定格式的代码就能完成整个开发。但是随着这类应用的增长规模及作用范围的变化,复杂的维护性问题就会随之而来。由于 UI控件 与 业务逻辑 之间的紧耦合,相应带来的问题就是 UI 变更的代价增大,以及难以编写针对性的单元测试。
使用 MVVM 模式来实现应用的主要动机有以下几点:
MVVM 模式
Model-View-ViewModel 的模式可以用到所有的 XAML 平台上。它的意图是在 UI 控件和它们的逻辑之间进行一个纯净的概念分离。
MVVM 模式中有三个核心的组件:model(模型),view(视图) 以及 view-model(视图模型)(译者注:为保证交流中术语的一致性,model、view、view-model后面均不作翻译),它们彼此间扮演一个截然不同的角色。下面的插图展示了这三个组件之间的关系:
每个组件之间都是相互解耦的,这也使得:
除了理解这三个组件的职责,理解组件之间是如何交互的也同样重要。在最高的层级上,view 能感知到 view-model,view-model 能感知到 model,但是 model 并不会察觉到 view-model 的存在,同样的,view-model 也察觉不到 view。
view-model 将 model 类 与 view 隔离开来,这也使得 model 可以独立于 view 进行演化。
View
view 的职责是用来定义 结构、布局,及用户在屏幕上看到的外观表现。理想情况下,view 仅通过 XAML 定义,以及一些有限的不包含业务逻辑的代码。
在一个 Windows Phone 应用中,view 通常是一个页面。除此之外,一个 view 也可以是一个父 view 的子组件,或者一个 ItemsControl 中的 DataTemplate对象。
一个 view 可以有自己的 view-model,或者继承自父级 view 的 view-model。视图通过绑定,或者调用 view-model 上的方法来获取数据。在运行期间,UI 控件将会响应 view-model 属性触发的变化通知,从而改变 view。
有一些 view 上的交互会触发 view-model 上的代码执行,比如说按钮点击或者选项选中事件。如果这个控件是一个命令源,这个控件的 Command 属性可以在 view-model 上绑定成一个 ICommand 属性。当这个控件的命令被调用,view-model 上相应的代码就会被执行。除了命令,行为也能被附加到 view 的一个对象中,然后监听命令调用及事件触发。作为回应,这个行为之后可以调用 view-mode 上的 ICommand 或者方法。(译者:web 领域里这些就是指的模板上的事件绑定语法,通常由框架提供)
Model
model 在 MVVM 中是应用的域模型(domain model)实现,它包含数据模型以及相应的业务和校验逻辑。model 对象的例子包括,数据仓库(repositories),业务对象,数据转换对象(DTOs),POCO对象,以及生成的实体及代理对象。
view-mode 作为 view 和 model 的中间人,它的职责是用于处理 view 的逻辑。通常情况下,view-model 与 model 之间的交互是通过调用 model 类中的方法来完成的。之后 view-model 依据 model 中的数据提供一种方便 view 使用的格式。view-model 从 model 中获取数据然后使其对 view 可用的同时,为了让 view 操作起来更简单,可能会通过一些方式做数据格式转换。view-model 还提供了一些命令的实现让应用的用户可以在 view 中使用。比如说,当用户点击了 UI 中的一个 button,这个动作可以触发 view-model 中的一个命令。view-model 同样有职责去定义一些某些方面会影响 view 展示的逻辑状态的变化,比如说一个表明一些操作是挂起的状态。
为了让 view-model 参与到与 view 的双向数据绑定当中,它的属性必须触发 PropertyChanged 事件。
(译者注:后面这两段是基于 .NET 平台的具体代码实践,换算到 web 领域,基本上说的就是在 VM 中监听数据变化,然后做出对应的反应。)
View-model 通过实现 INotifyPropertyChanged 接口以及属性变化时触发的 PropertyChanged 事件来满足这个需求。当属性发生变更时,监听者可以适当做回应。
对于集合而言,相应的提供了视图友好的工具System.Collections.ObjectModel.ObservableCollection 。这个工具实现了集合变更通知,从而减轻了开发者自己在集合上实现 INotifyCollectionChanged 接口的负担。
MVVM 利用了 Silverlight 中的数据绑定能力以及行为和事件触发器来管理 view 和 view-model 之间的联系。这些能力将业务代码需要出现在视图代码中必要性变得很低。
有很多用来连接 view-model 和 view 的方法,包括直接的关系以及基于容器的方式。然而,所有的方式共有的一个目标就是,给 view 的 DataContext 属性分配一个 view-model。
Views 可以与 view models 在独立代码文件里建立连接,也可以直接在 view 中。
一个 view 的代码可以是在独立代码文件中,于此同时 view-model 需要分配成它的 DataContext 属性。这可以是通过一个简单的 view 初始化一个新的 view-model 然后分配给它的 DataContext 属性来完成,也可以通过 view 使用控制反转(IOC)容器注入一个 view-model 来实现。
但是,在独立代码中 连接一个 view-model 到 view 中的做法是不推荐的,它可能给同时使用 VS 及 MSB(Microsoft Expression Blend®) 设计软件的设计师造成问题。View
如果一个 view-model 没有任何的构造器参数,它可以被当做 view 的 DataContext 来实例化。一个通常的实现方法是使用一个 view-model 定位器。这个资源可以公开应用的 view models 作为属性,从而使得独立的 view 可以绑定上去。这种方式意味着应用只有一个类用来连接 view models 到 views。此外,它仍然让开发者可以自由选择手动执行 view-model 定位器内的连接,或者使用一个依赖注入容器。
MVVM 使得完美的 开发-设计 工作流变为可能,它具备以下优点:
更多关于 MVVM 的信息,参考以下文档: Implementing the MVVM Pattern Advanced MVVM Scenarios
译者按:
MVVM 作为2005年微软提出来的 UI 架构,我认为在经过这么多年的检验之后,还是非常值得信赖的。虽然在这一两年随着 React 的兴起,以及在前端领域“起死回生”的函数式编程,MVVM 被各种错误或‘恶意’的解读导致其花式被黑。但是在我看来,MVVM 作为一个完整的 GUI 架构,跟 Flux 流派的数据层架构本身理念上是并不冲突的。我们依然可以 M/VM 层实践 Flux。
我认为就前端领域而言,MVVM 最大的意义在于,如果我们能很干净的分离出应用的 view 和 M/VM,我们就可以使得整个应用的业务模型能独立于框架运行。相比于现在换一个框架就重写一次应用的做法(老实说我受够了而且觉得没什么价值),再结合当前前端‘欣欣向荣’的状态,如果能做到只需要花费很小的代价,我们就能快速的享受到新技术带来的红利,那基本上就非常美好了。