在此推荐自己开发的一款基于 Angular Material 的中后台管理框架。

Github: https://github.com/ng-matero/ng-matero

预览地址: https://ng-matero.github.io/ng-matero/

为什么使用 Angular

我不是 Angular 的布道者,但如今痴迷 Angular,使用 Angular 做项目让我有一种兴奋感。目前的三大主流前端框架都研究过,博客中也有三者的相关教程,最早接触的是 React,但是并没有实际的项目经验,只做过一些 Demo 。使用 Vue 做过一个比较复杂的移动端大数据项目,技术栈采用 Framework7 + Vue + Vuex,整体效果还是满意的。

因为去年的项目几乎都是后台管理系统,所以框架用的不多,主要还是传统方式开发,后期为了改善前端开发体验,逐步在向框架靠拢。通过第三方 Bootstrap 框架对比发现,大多都有 Angular 版本,而且组件库是最全的,React 和 Vue 版本的组件库相对匮乏一些。事实证明使用 Angular 开发大型后台管理系统具有独特的优势。另一方面, Angular 是困难度复杂度的一个缩影,它汇聚了设计模式、设计哲学、工程化思想,对于前端开发是质的飞越。 除此之外,Angular 的文档让我着迷,除了基本的教程之外,其核心知识是最让我津津乐道的地方,不仅可以了解技术内幕,甚至可以学习很多基础知识,都非常实用,对于前端新手以及业余爱好者都有很大的帮助作用。

使用 Angular 开发需要非常多的前置知识,比如 TypeScript、RxJS 等,所以学习成本比较高,这也是很多人望而却步的一个原因。在经过很长时间的学习及准备之后,终于在今年有了项目实战的机会,项目很小,是整个系统中的一个独立模块,但是几乎所有知识都有涉猎,可谓“麻雀虽小五脏俱全”。本文就是对该项目的一些总结及思考。

搭建开发环境

开发环境的搭建非常简单,使用 Angular CLI 几乎可以完成所有工作,但是在与后端联调接口的时候,还需要做一些自定义配置。以下是 proxy.config.json 文件的基本设置:

{
"/api": {
"target": "http://localhost:3000",
"secure": false
}
}

Angular CLI 的使用贯穿整个项目,从开发到打包无处不在,这也是 Angular 工程化的体现。因为 CLI 的参数非常多,必须仔细阅读文档,合理设置参数,所有的需求几乎都能在参数中找到。其中使用 ng build 打包后可能会有资源引用错误的问题,可以看一下使用 ng build 构建后资源地址引用错误的问题

在联调接口时,可能还会遇到传输 Cookie 的问题,具体可以参见 关于 Angular 跨域请求携带 Cookie 的问题

选择 UI 库

因为项目比较小,开发之初打算自己写组件,比如分页,但实际情况比较复杂,尤其刚接触 Angular,对于组件交互、异步数据还有点懵,尝试写了一下,仍然有很多问题,所以最终还是选择比较成熟的 UI 库。

UI 库的选择需要根据样式决定,比如我的项目使用的是 Bootstrap,所以 UI 库选择了和 Bootstrap 相关的 ngx-bootstrap。对于后台管理系统,常用的组件无外乎弹窗、分页、标签页等。对于更复杂的系统,也可以根据自己的情况选择其他组件更丰富的 UI 库,比如 PrimeNG 等。

组件库主要使用了弹窗及分页,其中 ngx-bootstrap 的弹窗是一个比价优秀的组件,信息输入及提示都会用到。以下是一个自定义 Alert 弹窗,通过 Service 共享组件即可。

modal-alert.component.html 中的代码是整个组件的 HTML 结构,有两个变量及一个实例方法。

<div class="modal-header">
<h4 class="modal-title pull-left">{{title}}</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="bsModalRef.hide()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
{{content}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" (click)="bsModalRef.hide()">关闭</button>
</div>

modal-alert.component.ts 中定义变量及组件实例。

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

import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';

@Component({
selector: 'app-modal-alert',
templateUrl: './modal-alert.component.html',
styleUrls: ['./modal-alert.component.css']
})
export class ModalAlertComponent implements OnInit { title: string;
content: string; constructor(public bsModalRef: BsModalRef) {} ngOnInit() {
} }

modal.service.ts 中定义了组件的公共方法 modalAlert()

export class ModalService {
modalRef: BsModalRef; constructor(private modalService: BsModalService, private http: HttpClient) { } modalAlert(msg: string) {
const initialState = {
content: msg,
title: '提示信息'
};
this.modalRef = this.modalService.show(ModalAlertComponent,
{
initialState: initialState,
class: 'modal-sm'
}
);
}
}

最后还需要在 app.module.ts 中定义 entryComponents,比如:

@NgModule({
declarations: [
...
],
imports: [
...
],
...
entryComponents: [ModalAlertComponent, ModalConfirmComponent]
})

还有一点需要注意,在使用模板引用变量时,不要和函数名重名,有时图省事可能会忽略这一点。比如以下代码会报错:

<ng-template #Alert>
...
<div class="modal-footer">
<button type="button" class="btn btn-primary" (click)="Alert()">确定</button>
</div>
</ng-template>

表单的多样性

Angular 提供了两种表单,模板驱动表单响应式表单。其中模板驱动表单简单灵活,适用于不复杂的表单数据。

关于表单这一块,我们将 Angular 和 Vue 放在一起说,Vue 的表单绑定就属于模板驱动表单。不过 Angular 的模板驱动表单并没有复选框的多选绑定,如果有这个需求,可以选择更加灵活强大的响应式表单进行数据绑定。其实,对于数组形式的数据可以使用天然的 select 多选框实现。比如以下代码:

<div class="form-group">
<label for="power">Hero Power</label>
<select class="form-control" id="power"
multiple
required
[(ngModel)]="model.power"
name="power">
<option *ngFor="let pow of powers" [value]="pow">{{pow}}</option>
</select>
</div>

关于数组类型的数据,在 Vue 中有两种绑定方法,分别是复选框及 select 多选框。然而复选框的 value 值只有 true 或者 false,而 select 多选框的 value 值就是数组。所以 Vue 对复选框的多选操作进行了处理,而 Angular 没有,需要你自己处理。通过 Angular 的响应式表单可以很容易实现。但是对于模板驱动表单也可以用另类的方式实现,比如手动实现一个双向数据绑定,虽然有点麻烦,但却是可行的。关于这个话题我放到下一篇文章中说明。

官方文档中关于表单的内容非常详细,从用户输入到绑定再到校验,比着葫芦画瓢就可以轻松实现双向数据绑定。我非常喜欢 Angular 中 [()] (盒子里的香蕉)这种数据绑定方式,通过阅读官方文档的核心知识,对于双向数据绑定的认识有了质的提高。

管道之数据映射

管道的用处非常大,就我个人而言,时间转换及数据映射比较常见。我主要想讨论一下数据映射的问题。起初打算自己写关于数据映射的管道,但是想了想,难道不同的数据映射都单独写一个管道?然后我就想有没有自带的管道实现数据映射,仔细翻了翻文档,最后终于找到了,I18nPluralPipe 就是用于映射数据的。我们用一个最常见的数据映射例子说明,比如保存性别数据时,1 表示男,2 表示女。

@Component({
selector: 'i18n-plural-pipe',
template: `<div>{{ sex | i18nPlural: sexMapping }}</div>`
})
export class I18nPluralPipeComponent {
sex: string = '1';
sexMapping: {[k: string]: string} = {'=1': '男', '=2': '女', 'other': '其他'};
}

I18nPluralPipe 使用了 ICU 格式,确实长见识了。这个管道真的很好用,至少不用对每一个数据映射都写一个专用管道了。

上方示例代码中, sexMapping 使用接口中的可索引的类型进行定义。

异步开发之 RxJS

关于 RxJS 是一个比较复杂的话题,我也没有完全弄明白。Angular 官网的定义如下:

响应式编程是一种面向数据流和变更传播的异步编程范式(Wikipedia)。RxJS(响应式扩展的 JavaScript 版)是一个使用可观察对象进行响应式编程的库,它让组合异步代码和基于回调的代码变得更简单 (RxJS Docs)。

关于异步开发的历史在面试中有遇到过,可以说的东西很多,比如回调函数、Promise、迭代器和生成器、async 和 await,除此之外,RxJS 中的可观察对象(Observable)应该是下一个更强大的异步编程方式。Angular 官网对可观察对象(Observable)和承诺(Promise)进行了对比

需要特别注意的就是,只有当订阅 Observable 的实例时,它才会开始发布值。 订阅时要先调用该实例的 subscribe() 方法,并把一个观察者对象传给它,用来接收通知。我刚开始使用时,也是因为这个原因被坑了一把。以下是一个很简单的官方示例:

import { ajax } from 'rxjs/ajax';

// 创建一个发送 AJAX 请求的 Observable 对象
const apiData = ajax('/api/data');
// 订阅请求
apiData.subscribe(res => console.log(res.status, res.response));

总结

这个简单的小项目用了大约一周多的时间,Angular 算是入门了,关于 Angular 还有非常多值得深究的知识。整体而言,Angular + TypeScript 的开发方式非常舒服,VSCode 对 TS 的支持非常完美,语法提示、自动补全都很方便,强类型语言是前端开发的趋势。使用 Angular 开发,正如我文章开头提到的一样,不仅仅是学习一个框架,而是学习一种思想,了解更加优秀的开发模式、开源项目,可以让自己始终站在技术的前沿,这是我最大的收获。

如果大家喜欢 Angular 或者对 Angular Material 感兴趣,欢迎进群讨论!

浅谈 Angular 项目实战的更多相关文章

  1. 浅谈Angular的 $q, defer, promise

    浅谈Angular的 $q, defer, promise 时间 2016-01-13 00:28:00  博客园-原创精华区 原文  http://www.cnblogs.com/big-snow/ ...

  2. 浅谈开源项目Android-Universal-Image-Loader(Part 3.1)

    本文转载于:http://www.cnblogs.com/osmondy/p/3266023.html 浅谈开源项目Android-Universal-Image-Loader(Part 3.1) 最 ...

  3. 浅谈angular框架

    最近新接触了一个js框架angular,这个框架有着诸多特性,最为核心的是:MVVM.模块化.自动化双向数据绑定.语义化标签.依赖注入,以上这些全部都是属于angular特性,虽然说它的功能十分的强大 ...

  4. 浅谈tornado项目应用设计

    一.预备知识 最近开始尝试做一些tornado商城项目,在开始之前需要引入一些项目设计知识,如接口,抽象方法抽象类,组合,程序设计原则等,个人理解项目的合理设计可增加其灵活性,降低数据之间的耦合性,提 ...

  5. 浅谈Androidclient项目框架

    写Android也有些时间了,一边工作,一边学习,一边积累.仅仅有遇到问题了,花时间去研究,自己的能力才干提升.刀假设不用.慢慢的就会生锈应该也是这个道理吧!上个月公司项目server框架进行的一些调 ...

  6. 浅谈 angular新旧版本问题

    一直在学习angularJs,之前用的版本比较老,前些天更新了一下angularJs的版本,然后发现了一些问题,希望和大家分享一下. 在老的版本里控制器直接用函数定义就可以 比如: 在angularJ ...

  7. 浅谈Vue 项目性能优化 经验

    我优化公司的项目总结的几点: 1.先查看引入的图片大小,如果太大了,可以压缩,压缩路径:https://zhitu.isux.us/ 2.代码包优化, 待下项目开发完成.进行打包源码上线环节,需要对项 ...

  8. [原创] 浅谈开源项目Android-Universal-Image-Loader(Part 3.1)

    最近,总算有时间去做些平时喜欢而没空去做的事情.一直觉得项目中使用的Image Loader适用性不强,昨晚在github随便逛逛,发现一个开源项目Android-Universal-Image-Lo ...

  9. 浅谈angular中的promise

    promise目的就是为了跳出回调地狱.老掉牙的东西,大神轻拍. 举个最简单的例子:请求数据(getData),解析数据(executeData),显示数据(showData). //获取数据 fun ...

随机推荐

  1. 做自己的CEO

    目录 前言 做自己的CEO 做自己的CEO是指什么 为什么要做自己的CEO 如何做自己的CEO 定义自己的愿景.使命和价值观 愿景 (Vision) 使命 (Mission) 价值观 (Values) ...

  2. 解决ASP.NET Core MVC调试慢的问题

    最近在做的一个项目中,发现网页端同时发起了4个AJAX请求需要数秒才获取到响应,太慢了,当我把请求数降低为1个的时候,速度看起来就比较正常,增加到2个同时的请求后,速度就有些慢了,3个的话就明显慢了, ...

  3. perl学习笔记--搭建开发环境

    windows下perl开发环境搭建 perl下载地址:http://www.activestate.com/developer-tools 各个插件的安装方法:(通过代理上网的方法) 方法一:pad ...

  4. .NET Core微服务之基于Jenkins+Docker实现持续部署(Part 1)

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.CI, CD 与Jenkins 互联网软件的开发和发布,已经形成了一套标准流程,最重要的组成部分就是持续集成(Continuous i ...

  5. 如何在ASP.NET Core程序启动时运行异步任务(2)

    原文:Running async tasks on app startup in ASP.NET Core (Part 2) 作者:Andrew Lock 译者:Lamond Lu 在我的上一篇博客中 ...

  6. Win32对话框程序(1)

    之前学C语言是一直都是在控制台下面操作的,面对的都是黑框框,严重的打击了学习的兴趣.后来在TC下进行C语言课程设计,做了图形界面编程,但都是点线面画的…… 中间隔了好长一段时间没有碰过C语言,最近才开 ...

  7. JAVA WEB快速入门之从编写一个基于SpringMVC框架的网站了解Maven、SpringMVC、SpringJDBC

    接上篇<JAVA WEB快速入门之通过一个简单的Spring项目了解Spring的核心(AOP.IOC)>,了解了Spring的核心(AOP.IOC)后,我们再来学习与实践Maven.Sp ...

  8. 数据结构——Java实现顺序栈

    一.分析 栈是限定仅在表的一端进行插入或删除操作的线性表,对于栈来说,操作端称为栈顶,另一端则称为栈底,栈的修改是按照后进先出的原则进行的,因此又称为后进先出的线性表. 顺序栈是指利用顺序存储结构实现 ...

  9. jQuery(七)、效果和动画

    1 显示和隐藏 1.show([speed,[easing],[fn]]) 显示隐藏的匹配元素. 参数: (1) spend:三种预定速度之一的字符串('show','normal','fast')或 ...

  10. 微信小程序 canvas 文字居中

    drawCanvas: function(ctx) { //... // 昵称 ctx.setFontSize(16) //字体大小 ctx.setFillStyle('#fff') //字体颜色 c ...