前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在前端中理解MVC服务之 Angular篇(完结)

在前端中理解MVC服务之 Angular篇(完结)

作者头像
学前端
发布2020-04-07 15:39:54
4K0
发布2020-04-07 15:39:54
举报
文章被收录于专栏:前端之巅前端之巅

介绍

本文是该系列中的第三篇,旨在了解 MVC 体系结构如何创建前端应用程序。目的是了解如何构建前端应用程序。这是通过从使用 JavaScript 作为脚本语言的网页演变为使用 JavaScript/TypeScript 作为面向对象语言的应用程序来实现的。在第三篇文章中,应用程序将使用 Angular 构建,该版本来自TypeScript 的第二个版本。因此,本文介绍应用程序从 TypeScript 到Angular的迁移。但是,了解应用的所有部分如何相关联以及其结构方式非常重要。角度允许我们忘记DOM,所以,让user.view.ts文件从我们的应用中消失。最后,在最后一篇文章中,我们将转换代码以将其与 Angular 框架集成。

  • 第 1 部分。了解前端的 MVC 服务:VanillaJS 点击直达
  • 第 2 部分。了解前端的 MVC 服务:TypeScript 点击直达
  • 第 3 部分。了解前端的 MVC 服务:Angular 点击直达

项目架构

什么是MVC架构?

MVC 架构是一个具有三个层/部分的体系

  • Model -管理应用的数据,这些模型将是不可见的,因为它们将被引用于服务。
  • View 模型的直观表示,即用户所看到的部分
  • Controller - Model与View中的链接

下图是我们的项目结构

该文件将充当一个画布,使用 元素动态构建整个应用程序。最后,我们的文件架构由以下JavaScript文件组成:

  • user.model.ts —用户的属性(模型)
  • user.service.ts —管理用户的所有操作
  • users.component.ts 负责加入Service和View的部分
  • users.component.html —负责刷新和更改显示屏幕

应用模块如下所示:

import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { UserService } from './shared/services/user.service';
import { UsersComponent } from './views/users/users.component';

@NgModule({
  declarations: [AppComponent, UsersComponent],
  imports: [BrowserModule, FormsModule, ReactiveFormsModule],
  providers: [UserService],
  bootstrap: [AppComponent]
})
export class AppModule {}

我们可以看到,在我们的应用中有三个模块:BrowserModuleFormsModulereactiveFormsModule,第一个模块用于从 Angular 获取基本结构和属性指令,而第二个和第三个模块用于创建窗体。但在此示例中,我们的目标是向您展示从 JavaScript 到 Angular 的演化过程。

Models (贫血模式)

此示例中的第一个生成类是应用程序模型,user.model.ts由类属性和生成随机 D 的私有方法(这些代码可能来自服务器中的数据库)。模型将具有以下字段:

  • id 唯一值
  • name 用户名
  • age 用户年龄
  • complete bool值,可以知道此条数据是否有用

用户的Class已经被写在TS中。不管怎么样,该对象从Localstorage中构建一个接受一个普通对象,该对象将会提供数据。此纯对象必须符合接口,以便任何纯对象都不能实例化,而是满足定义的接口对象。 user.model.ts如下列代码所示:

export interface UserDto {
  name: string;
  age: string;
  complete: boolean;
}

export class User {
  public id: string;
  public name: string;
  public age: string;
  public complete: boolean;

  constructor(
    { name, age, complete }: UserDto = {
      name: null,
      age: null,
      complete: false
    }
  ) {
    this.id = this.uuidv4();
    this.name = name;
    this.age = age;
    this.complete = complete;
  }

  uuidv4(): string {
    return (([1e7] as any) + -1e3 + -4e3 + -8e3 + -1e11).replace(
      /[018]/g,
      (c: number) =>
        (
          c ^
          (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
        ).toString(16)
    );
  }
}

Service

对用户执行的操作在Service中执行。该服务允许Model贫血化,因为所有的逻辑负载都在其中。在此特定情况下,我们将使用数组来存储所有用户,并生成与读取、修改、创建和删除 (CRUD) 用户关联的四种方法。您应该注意,Service使用Model,将从Localstarage中提取的对象实例化到 。这是因为Localstarage只存储数据,而不是存储数据的原型。从后端到前端的数据也是如此:它们没有实例化其Class.

我们Class的构造函数如下:

constructor() {
  const users: UserDto[] = JSON.parse(localStorage.getItem('users')) || [];
  this.users = users.map(user => new User(user));
}

我们定义了一个名为"类变量"的类变量,该变量在所有用户从纯对象转换为Class的原型对象后存储它们。

在服务中我们必须定义的下一件事是我们想要开发的每个操作。使用 TypeScript 如下所示:

add(user: User) {
    this.users.push(new User(user));
    this._commit(this.users);
  }

  edit(userID: string, userToEdit: User) {
    this.users = this.users.map(user =>
      user.id === userID
        ? new User({
            ...user,
            ...userToEdit
          })
        : user
    );

    this._commit(this.users);
  }

  delete(userID: string) {
    this.users = this.users.filter(({ id }) => id !== userID);
    this._commit(this.users);
  }

  toggle(userID: string) {
    this.users = this.users.map(user =>
      user.id === userID
        ? new User({ ...user, complete: !user.complete })
        : user
    );

    this._commit(this.users);
  }

这个负责存储在Localstarage中的方法仍然有待定义:

_commit(users: User[]) {
  localStorage.setItem('users', JSON.stringify(users));
}

此方法不会调用创建服务时绑定的函数,在 JavaScript 或 TypeScript 中开发时callback是必需的,因为 Angular 执行此任务,在Cont和Model之间执行绑定。 user.service.ts 文件如下所示:

import { User, UserDto } from "../models/user.model";

export class UserService {
  public users: User[];

  constructor() {
    const users: UserDto[] = JSON.parse(localStorage.getItem("users")) || [];
    this.users = users.map(user => new User(user));
  }

  _commit(users: User[]) {
    localStorage.setItem("users", JSON.stringify(users));
  }

  add(user: User) {
    this.users.push(new User(user));
    this._commit(this.users);
  }

  edit(userID: string, userToEdit: User) {
    this.users = this.users.map(user =>
      user.id === userID
        ? new User({
            ...user,
            ...userToEdit
          })
        : user
    );

    this._commit(this.users);
  }

  delete(userID: string) {
    this.users = this.users.filter(({ id }) => id !== userID);
    this._commit(this.users);
  }

  toggle(userID: string) {
    this.users = this.users.map(user =>
      user.id === userID
        ? new User({ ...user, complete: !user.complete })
        : user
    );

    this._commit(this.users);
  }
}

Views

这个部分与前两篇文章相比,是变化最大的一部分,在这种情况之下,我们不需要使用DOM,因为Angular将执行动态操作 DOM 的艰巨任务。但是,我们必须正确定义模板。

下面是为此示例创建的模板(一个角度丰富的 HTML 版本):

<h1>Users</h1>

<form [formGroup]="userForm" (ngSubmit)="add(userForm.value)">
  <input
    type="text"
    placeholder="Name"
    name="name"
    formControlName="name"
  /><input
    type="text"
    placeholder="Age"
    name="age"
    formControlName="age"
  /><button>Submit</button>
</form>
<ul class="user-list">
  <li *ngFor="let user of users">
    <input type="checkbox" (change)="toggle(user)" [checked]="user.complete" />
    <span>
      <s *ngIf="user.complete; else uncompleteName">{{ user.name }}</s>
      <ng-template #uncompleteName>{{ user.name }}</ng-template>
    </span>
    <span
      #age
      contenteditable="true"
      class="editable"
      (focusout)="edit(user, age)"
    >
      <s *ngIf="user.complete; else uncompleteAge">{{ user.age }}</s>
      <ng-template #uncompleteAge>{{ user.age }}</ng-template></span
    >
    <button class="delete" (click)="delete(user)">Delete</button>
  </li>
</ul>

这不是一个Angular教程,而是一系列的变化,你可以看到Web应用程序从JavaScript到TypeScript到Angular的演变。

但是,我们注意到,前几部分中的许多 DOM 操作代码已通过 Angular 得到解决,它们提供了两个结构指令,如 @ ngFor 和 _ ngIf,它们允许从模板本身轻松操作 DOM。

另一个有趣的点是,Angular 在此示例中帮助我们使用反应形式。有了这些,模板连接到控制器,而无需我们发送处理程序来建立连接。

Controller

此体系结构的最后一个文件则是Controller(user.controller.ts)。Controller将通过依赖注入(DI)接收其具有的两个依赖项(ServiceformBuilder).这些依赖项将存储在Controller中的私有变量。

Controller仅侧重于管理连接到View(模板)的属性并调用Service。与我们的第一个 JavaScript 代码或前几篇文章的第二个 TypeScript 版本完全一样。在这种情况下,我们离开了框架与 DOM 关联的所有任务。这是users.component.ts 文件:

import { Component, OnInit } from '@angular/core';

import { FormBuilder } from '@angular/forms';
import { UserService } from 'src/app/shared/services/user.service';

@Component({
  selector: 'app-users',
  templateUrl: './users.component.html',
  styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {
  public users;
  public userForm;

  constructor(
    private userService: UserService,
    private formBuilder: FormBuilder
  ) {
    this.userForm = this.formBuilder.group({
      name: '',
      age: ''
    });
  }

  ngOnInit() {
    this.refreshUsers();
  }
  refreshUsers() {
    this.users = this.userService.users;
  }

  add(userForm) {
    this.userService.add(userForm);
    this.refreshUsers();
    this.userForm.reset();
  }
  delete({ id }) {
    this.userService.delete(id);
    this.refreshUsers();
  }
  edit(user, { innerText: age }) {
    const { id } = user;
    this.userService.edit(id, { ...user, age });
    this.refreshUsers();
  }
  toggle({ id }) {
    this.userService.toggle(id);
    this.refreshUsers();
  }
}

总结

在第三部分中,我们开发了一个 Web 应用程序,其中项目的结构遵循 MVC 体系结构,其中使用了贫血模型,逻辑的责任在于Service

需要强调的是,这篇文章的要点是,让你了解不同文件中具有不同功能的项目结构,以及View如何完全独立于Model/Service和Controller。

还必须注意的是,在本文中,我们将应用程序从 TypeScript 迁移到了 Angular,让我们忘记了那些与我们开发的所有 Web 应用程序都相同的重复任务。

我建议你从第一篇与JavaScript相关的帖子开始,了解所使用的体系结构。下一步是通过应用 TypeScript(在第二篇文章中)来强化代码,最后查看此文章中的代码已适应框架。

本文原文来自Medium 本文仅做翻译。 原作者:Carlos Caballero 如需转载,请注明原创

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一起学前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 项目架构
  • 什么是MVC架构?
    • 下图是我们的项目结构
      • 应用模块如下所示:
      • Models (贫血模式)
      • Service
      • Views
      • Controller
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档