Angular 结合 NG-ZORRO 快速开发

简介: 连更的这几天的文章,我们已经了解了不少 angular 的知识点了,这次我们来个小成品。angualr 结合 ng-zorro 快速且规范的开发一个后台系统。

image.png


一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情


连更的这几天的文章,我们已经了解了不少 angular 的知识点了,这次我们来个小成品。


angualr 结合 ng-zorro 快速且规范的开发一个后台系统。


系统功能包括下面的内容:


  • 欢迎页面
  • 用户列表
  • 用户新增
  • 用户修改
  • 用户删除


所有的 service 使用模拟的数据。


说干咱就干。


结合 ng-zorro



angular 比较流行的 ui 框架有:


  • Angular Material 官方指定 UI 框架
  • NG-ZORRO,又名 Ant Design of Angular 国内比较流行的 UI 框架


Ant Design 相信做前端开发的人儿都比较熟悉了。所以这里我们结合 NG-ZORRO 这个框架来做。如果熟悉 Vue 或者 React 版本的 Ant Design,相信你可以无缝链接啊~


我们重新使用 angular-cli 生成一个项目 ng-zorro。如果你还不了解相关的 angular 主要内容,请先前往文章了解 Angular 开发的内容


添加 ng-zorro 是很简单的事情:进入 ng-zorro 根目录,执行 ng add ng-zorro-antd 即可。


当然你也可以执行 npm install ng-zorro-antd 添加,不推荐。


结合 ng-zorro 完成之后,我们运行项目起来 npm run start,你会在 http://localhost:4200 的页面看到下图内容。



Not Bad, Bro.


配置路由



我们改成 hash 路由,并添加用户路由,脚手架都帮我们完事了,我们只要做点小修改。


思路:


  1. 先添加页面 user 用户的列表页面,使用 ng-zorrotable 组件


  1. 用户的新增和更改页面可以共用同一个页面,使用 ng-zorroform 组件


  1. 页面删除功能直接使用弹窗提示,使用 ng-zorromodal 组件


  1. ng-zorro 组件按需引入


  1. 调整路由文件


按照思路,我们得在 ng-zorro 引入:


// app.module.ts
import { ReactiveFormsModule } from '@angular/forms';
import { NzTableModule } from 'ng-zorro-antd/table';
import { NzModalModule } from 'ng-zorro-antd/modal';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzFormModule } from 'ng-zorro-antd/form';
import { NzInputModule } from 'ng-zorro-antd/input';
// ...
imports: [ // 是在 imports 中添加,而不是 declarations 中声明
  NzTableModule,
  NzModalModule,
  NzButtonModule,
  NzFormModule,
  ReactiveFormsModule,
  NzInputModule
],
复制代码


简单易理解原则,我们这里不使用 children 进行路由的嵌套:


// app.routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule, PreloadAllModules } from '@angular/router';
import { WelcomeComponent } from './pages/welcome/welcome.component';
import { UserComponent } from './pages/user/user.component';
import { UserInfoComponent } from './pages/user/user-info/user-info.component';
// 相关的路由
const routes: Routes = [
  { 
    path: '', 
    pathMatch: 'full', 
    redirectTo: '/welcome' 
  },
  {
    path: 'welcome',
    component: WelcomeComponent
  },
  {
    path: 'user',
    component: UserComponent
  },
  {
    path: 'user/add',
    component: UserInfoComponent
  },
  {
    path: 'user/edit/:uuid',
    component: UserInfoComponent
  }
];
@NgModule({
  imports: [RouterModule.forRoot(
    routes,
    {
      useHash: true,// 使用 hash 模式
      preloadingStrategy: PreloadAllModules
    }
  )],
  exports: [RouterModule]
})
export class AppRoutingModule { }
复制代码


更改菜单



使用脚手架生成的菜单与我们需要开发的功能不符合,我们来调整下。


// app.component.html
<nz-layout class="app-layout">
  <nz-sider class="menu-sidebar"
            nzCollapsible
            nzWidth="256px"
            nzBreakpoint="md"
            [(nzCollapsed)]="isCollapsed"
            [nzTrigger]="null">
    <div class="sidebar-logo">
      <!-- 默认点击 logo 跳转到首页 -->
      <a routerLink="/welcome">
        <img src="https://ng.ant.design/assets/img/logo.svg" alt="logo">
        <h1>Ng-Zorro</h1>
      </a>
    </div>
    <ul nz-menu nzTheme="dark" nzMode="inline" [nzInlineCollapsed]="isCollapsed">
      <li nz-submenu nzOpen nzTitle="用户管理" nzIcon="dashboard">
        <ul>
          <li nz-menu-item nzMatchRouter>
            <a routerLink="/user">用户列表</a>
          </li>
        </ul>
      </li>
    </ul>
  </nz-sider>
  <nz-layout>
    <nz-header>
      <div class="app-header">
        <span class="header-trigger" (click)="isCollapsed = !isCollapsed">
            <i class="trigger"
               nz-icon
               [nzType]="isCollapsed ? 'menu-unfold' : 'menu-fold'"
            ></i>
        </span>
      </div>
    </nz-header>
    <nz-content>
      <div class="inner-content">
        <router-outlet></router-outlet>
      </div>
    </nz-content>
  </nz-layout>
</nz-layout>
复制代码


菜单展示,如果我们需要做权限管理的话,是需要后端配合进行传值的,然后我们再把相关的权限菜单渲染到页面


替换成上面的代码后,得到的基本骨架如下:


image.png


完成用户列表



接下来完成用户列表的骨架,因为使用了 UI 框架,我么写起来异常的方便:


获取用户列表


// user.component.html
<nz-table #basicTable [nzData]="list">
  <thead>
    <tr>
      <th>Name</th>
      <th>Position</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <!-- 对获取到的数据进行遍历 -->
    <tr *ngFor="let data of basicTable.data">
      <td>{{data.name}}</td>
      <td>{{data.position}}</td>
      <td>
        <a style="color: #f00;">Delete</a>
      </td>
    </tr>
  </tbody>
</nz-table>
复制代码


我们模拟了些数据在 assets 文件夹中 user.json:


{
  "users": [
    {
      "uuid": 1,
      "name": "Jimmy",
      "position": "Frontend"
    },
    {
      "uuid": 2,
      "name": "Jim",
      "position": "Backend"
    }
  ],
  "environment": "development"
}
复制代码


编写好服务之后,我们调用获取用户的数据:


// user.component.ts
import { Component, OnInit } from '@angular/core';
import { UserService } from 'src/app/services/user.service';
@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.scss']
})
export class UserComponent implements OnInit {
  public list: any = []
  constructor(
    private readonly userService: UserService
  ) { }
  ngOnInit(): void {
    if(localStorage.getItem('users')) {
      let obj = localStorage.getItem('users') || '{}'
      this.list =  JSON.parse(obj)
    } else {
      this.getList()
    }
  }
  // 获取用户列表
  getList() {
    this.userService.getUserList().subscribe({
      next: (data: any) => {
        localStorage.setItem('users', JSON.stringify(data.users))
        this.list = data.users
      },
      error: (error: any) => {
        console.log(error)
      }
    })
  }
}
复制代码


因为没有引入后端服务,这里我们采用 localstorage 的方式记录状态。


上面完成后,我们得到列表信息如下:


image.png


新增用户和编辑用户


我们简单建立个表单,里面含有的字段就两个,分别是 nameposition。这两个功能是公用一个表单的~


我们在 html 中添加:


// user-info.component.html
<form nz-form [formGroup]="validateForm" class="login-form" (ngSubmit)="submitForm()">
  <nz-form-item>
    <nz-form-control nzErrorTip="请输入用户名!">
      <input type="text" nz-input formControlName="username" placeholder="请输入用户名" style="width: 160px;" />
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-control nzErrorTip="请输入职位!">
      <input type="text" nz-input formControlName="position" placeholder="请输入职位" style="width: 160px;"/>
    </nz-form-control>
  </nz-form-item>
  <button nz-button class="login-form-button login-form-margin" [nzType]="'primary'">确认</button>
</form>
复制代码


页面长这样子:


image.png


然后就是逻辑的判断,进行添加或者是修改。如果是连接带上 uuid 的标识,就表示是编辑,show you the codes


// user-info.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, ParamMap } from '@angular/router';
@Component({
  selector: 'app-user-info',
  templateUrl: './user-info.component.html',
  styleUrls: ['./user-info.component.scss']
})
export class UserInfoComponent implements OnInit {
  public isAdd: boolean = true;
  public userInfo: any = []
  public uuid: number = 0;
  validateForm!: FormGroup;
  constructor(
    private fb: FormBuilder,
    private route: ActivatedRoute,
  ) { }
  ngOnInit(): void {
    this.userInfo = JSON.parse(localStorage.getItem('users') || '[]')
    this.route.paramMap.subscribe((params: ParamMap)=>{
      this.uuid = parseInt(params.get('uuid') || '0')
    })
    // 是编辑状态,设置标志符
    if(this.uuid) {
      this.isAdd = false
    }
    if(this.isAdd) {
      this.validateForm = this.fb.group({
        username: [null, [Validators.required]],
        position: [null, [Validators.required]]
      });
    } else {
      let current = (this.userInfo.filter((item: any) => item.uuid === this.uuid))[0] || {}
      // 信息回填
      this.validateForm = this.fb.group({
        username: [current.name, [Validators.required]],
        position: [current.position, [Validators.required]]
      })
    }
  }
  submitForm() {
    // 如果不符合提交,则报错
    if(!this.validateForm.valid) {
      Object.values(this.validateForm.controls).forEach((control: any) => {
        if(control?.invalid) {
          control?.markAsDirty();
          control?.updateValueAndValidity({ onlySelf: true });
        }
      })
      return
    }
    // 获取到表单的数据
    const data = this.validateForm.value
    // 新增用户
    if(this.isAdd) {
      let lastOne = (this.userInfo.length > 0 ? this.userInfo[this.userInfo.length-1] : {});
      this.userInfo.push({
        uuid: (lastOne.uuid ? (lastOne.uuid + 1) : 1),
        name: data.username,
        position: data.position
      })
      localStorage.setItem('users', JSON.stringify(this.userInfo))
    } else { // 编辑用户,更新信息
      let mapList = this.userInfo.map((item: any) => {
        if(item.uuid === this.uuid) {
          return {
            uuid: this.uuid,
            name: data.username,
            position: data.position
          }
        }
        return item
      })
      localStorage.setItem('users', JSON.stringify(mapList))
    }
  }
}
复制代码


我们先设定一个标志符 isAdd,默认是新建用户;当 uuid 存在的时候,将其设置为 false 值,表示是编辑的状态,对内容进行表单的回填。提交表单的操作也是按照该标志符进行判断。我们直接对 localStorage 的信息进行变更,以保证同步列表信息。


删除功能


我们引入模态对话框进行询问是否删除。


// user.component.ts
// 删除
delete(data: any) {
  this.modal.confirm({
    nzTitle: '<i>你想删除该用户?</i>',
    nzOnOk: () => {
      let users = JSON.parse(localStorage.getItem('users') || '[]');
      let filterList = users.filter((item: any) => item.uuid !== data.uuid);
      localStorage.setItem('users', JSON.stringify(filterList));
      this.list = filterList
    }
  });
}
复制代码


image.png


我们找到删除的数据,将其剔除,重新缓存新的用户数据,并更新 table 的用户列表数据。


So,到此为止,我们顺利完成了一个简单的项目。我们用 Gif 图整体来看看。


image.png



相关文章
|
6月前
|
开发框架 前端开发 测试技术
什么是 Angular 企业级应用开发中的 Breaking Change
什么是 Angular 企业级应用开发中的 Breaking Change
48 0
|
7月前
|
Web App开发 存储 前端开发
使用 Chrome 开发者工具研究一个基于 Angular 开发的网站源代码
使用 Chrome 开发者工具研究一个基于 Angular 开发的网站源代码
41 0
|
3月前
|
存储 搜索推荐 API
通过项目中的实际例子,介绍 LocalStorage 在 Angular 开发中的使用场景
通过项目中的实际例子,介绍 LocalStorage 在 Angular 开发中的使用场景
37 0
|
5月前
|
Web App开发 缓存 前端开发
Angular 应用支持 PWA(Progressive Web Application) 特性的开发步骤分享
Angular 应用支持 PWA(Progressive Web Application) 特性的开发步骤分享
46 0
|
5月前
|
开发框架 前端开发 JavaScript
推荐一个前后端分离.NetCore+Angular快速开发框架
推荐一个前后端分离.NetCore+Angular快速开发框架
58 0
|
6月前
|
JavaScript 前端开发 测试技术
angular框架怎么从0到1进行开发
angular框架怎么从0到1进行开发
37 0
|
6月前
|
存储 JavaScript 前端开发
关于 Subscription 在 Angular 开发中的应用
关于 Subscription 在 Angular 开发中的应用
58 0
|
6月前
|
前端开发 测试技术
关于 fakeAsync 在 Angular 应用单元测试开发领域的使用介绍
关于 fakeAsync 在 Angular 应用单元测试开发领域的使用介绍
38 0
|
6月前
|
存储 缓存 JSON
用 Visual Studio Code 开发 Angular 应用自动生成的 .angular 文件夹
用 Visual Studio Code 开发 Angular 应用自动生成的 .angular 文件夹
32 0
|
6月前
|
测试技术 开发者
关于 Angular testing 开发包里 fakeAsync 测试工具的用法
关于 Angular testing 开发包里 fakeAsync 测试工具的用法
19 0

热门文章

最新文章