将MVVM应用于Angular2

时间:2017-04-10 06:16:23

标签: angular mvvm

使用angular2处理Web应用程序。 MVVVM模式:模型视图ViewModel,在angular2中我们有:模型类,可以从服务器端提取数据的服务以及视图和组件的模板。我想知道如何在angular2项目中正确应用MVVM架构?

1 个答案:

答案 0 :(得分:1)

在典型的MVVM模式中,您有Model对象(这是所有伪代码):

class MyModel { 
   public int id;
   public string foo;
   public int bar;
   public date createdOn;
}

然后你有了一个观点:

<div>{{myModelBar}}</div>
<div>{{myModelFoo}}</div>
<div>{{anotherModelBar}}</div>

您是否看到视图与模型之间没有关联?视图需要模型中的某些属性,但不是所有属性。该视图还需要模型中不存在的属性。这就是需要视图模型的地方:

class MyViewModel {
   public string myModelFoo;
   public int myModelBar;
   public int anotherModelBar;
}

现在我们的视图有一个它实际可以使用的模型。那么我们如何从Model到ViewModel到View呢?我们需要一个控制器:

class Controller() {
    var modelA = new MyModel();
    modelA.foo = "Foo";
    modelA.bar = 1;
    var modelB = new MyModel();
    modelB.bar = 2;

    var viewModel = new MyViewModel();
    viewModel.myModelFoo = modelA.foo;
    viewModel.myModelBar = modelA.bar;
    viewModel.anotherModelBar = modelB.bar;

    // The view function here would retrieve the view and combine it with the ViewModel
    var view = View('path_to_our_view_file', viewModel);

    return view;
}

这是MVVMC模式。我会插入并说MVVM模式本身是没用的,因为你的模型,视图和视图模型没有关于视图的任何行为或如何组成视图。我在声称是MVVM的框架中看到的是,ViewModel通常是Controller和ViewModel的混搭,或者他们认为模式是无控制器,因为没有路由。但是,我会说在ViewModel作用于特定视图的情况下隐含路由。

很明显,Angular并不严格遵守这种模式。但是,大多数概念都是类似的。你仍然有一个控制器和视图,它们只是以组件的形式混合在一起。就控制器而言,Angular 2的有趣之处在于您可以实际路由到控制器,并且您通过分配给组件的模板标签隐含了路由。但结果是一样的,您可以通过某种方式调用Component或将其路由到,从而检索视图。与许多框架一样,模型层由您自己创建。

那么ViewModel层在哪里?我建议由于View中可以访问Component中的所有公共变量,因此ViewModel层是Component类的属性。在客户端必须向服务器发出请求并且服务器返回视图的典型服务器客户端应用程序中,您需要在每次调用时重建状态。这要求您在每次通话时沿着MVVMC链走下去:控制器 - &gt;型号 - &gt; ViewModel - &gt;视图。在Angular中的客户端应用程序中,控制器保持视图的状态,因此这是ViewModel所在的位置。

所以问题就变成了,我们如何将View的关注点与模型的关注点分开。您只需要明智地不在视图中直接使用模型。一种方法是创建一个单独的视图模型作为类。

class MyComponentViewModel {
    name: string;
    list: Array<string>;
}

@Component({
    selector: 'my-component',
    template: `<div>{{model.name}}</div>
               <ul>
               <li *ngFor="let item of (model.list | async)">{{item}}</li>
               </ul>`
})
class MyComponent {
    model: MyComponentViewModel;
    private propertyA: string 

    constructor(private dataService: DataService) {
        this.model = new MyComponentViewModel();
        this.model.list = [];

        let page = dataService.getCurrentPage();
        let children = dataService.getPageChildren(page.id).subscribe(pages => {
            this.model.list = [];
            for(let page of pages) {
                this.model.list.push(page.title);
            }
        })

        this.model.name = page.title;
    }
}

这些代码都没有经过测试,希望你能得到重点。您可以创建自己的视图模型,而不是弄脏Component类的属性,您可以将视图属性放在它们自己的类中。这种方法的优点在于清洁组件和关注视图的分离,因为您现在有合同可以使用(只要您坚持使用该模式)。缺点是它有点冗长,可能很难将某些类型转换为更适合视图模型的更通用类型,因为您将所有属性放在一个对象上,因此可能会混淆角度变化检测(I我不确定这个。至于我,我可能不会使用这种模式,因为它看起来过于冗长。