README.md
目前为止Angular版本是11,利用TypeScript的装饰器(Decorators)特性,可以写类似Java Spring Boots面向切面风格的代码。没写过这样代码的人可能会不适应,其实基础好的话稍微看看官方文档可以马上上手。
项目介绍
本项目使用脚手架 Angular CLI
(version 11.2.12)
构建。UI使用 NG-ZORRO
(官网),这是 Ant Design 的 Angular 版。
目前只实现纯静态登陆。用户名: admin
密码: 123456
截图:
1. 默认登陆界面
2. 点击登陆按钮验证表单非空
3. 验证用户名密码错误
4. 登陆成功
项目目录
ng-demo
├── README.md
├── angular.json
├── e2e
│ ├── protractor.conf.js
│ ├── src
│ │ ├── app.e2e-spec.ts
│ │ └── app.po.ts
│ └── tsconfig.json
├── karma.conf.js
├── package.json
├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.html
│ │ ├── app.component.scss
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ └── components
│ │ ├── home
│ │ │ ├── home.component.html
│ │ │ ├── home.component.scss
│ │ │ └── home.component.ts
│ │ ├── login
│ │ │ ├── login.component.html
│ │ │ ├── login.component.scss
│ │ │ ├── login.component.ts
│ │ │ └── login.module.ts
│ │ └── ng-zorro-antd.module.ts
│ ├── assets
│ │ └── images
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ ├── polyfills.ts
│ ├── styles.scss
│ ├── test.ts
│ └── theme.less
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
└── tslint.json
项目说明
/src/app/app.modules.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LoginModule } from './components/login/login.module';
import { NZ_I18N } from 'ng-zorro-antd/i18n';
import { zh_CN } from 'ng-zorro-antd/i18n';
import { registerLocaleData } from '@angular/common';
import zh from '@angular/common/locales/zh';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
registerLocaleData(zh);
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
LoginModule,
FormsModule,
HttpClientModule,
BrowserAnimationsModule,
ReactiveFormsModule
],
providers: [{ provide: NZ_I18N, useValue: zh_CN }],
bootstrap: [AppComponent]
})
export class AppModule { }
- 引入路由模块
AppRoutingModule
、登陆模块LoginModule
、表单模块FormsModule
,并通过@NgModule
装饰器的imports
属性导入。 -
AppComponent
组件放在@NgModule
装饰器的declarations
属性 (可声明对象表) 和bootstrap
属性 (主视图,只有根模块才设置这个属性) 中。 - 关于
@NgModule
的使用,参考官方文档模块部分 。
/src/app/app.component.html
<router-outlet></router-outlet>
只有一个路由标签。
/src/app/app.routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './components/login/login.component';
import { HomeComponent } from './components/home/home.component';
const routes: Routes = [
{path: 'login', component: LoginComponent},
{path: '', redirectTo: '/login', pathMatch: 'full'},
{path: 'home', component: HomeComponent},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
- 设置路由的文件,项目启动后页面默认重定向到
/login
路由。 - 添加了
/home
路由,本实例暂时没用到。
/src/app/components/ng-zorro-antd.module.ts
...
import { NzButtonModule } from 'ng-zorro-antd/button';
...
@NgModule({
exports: [
...
NzButtonModule,
...
]
})
export class NgZorroAntdModule {}
- 这个文件从
ng-zorro-antd
中取得所有组件Module
并通过@NgModule
装饰器的exports
属性导出。
/src/app/components/login/login.moudle.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { LoginComponent } from './login.component';
import { NgZorroAntdModule } from '../ng-zorro-antd.module';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@NgModule({
declarations: [
LoginComponent
],
imports: [
BrowserModule,
NgZorroAntdModule,
FormsModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [
LoginComponent
]
})
export class LoginModule { }
- 这里引入了刚才定义的
ng-zorro-antd
导出的模块NgZorroAntdModule
,可用在html
部分,例如一个普通按钮<button nz-button>按钮</button>
标签, 增加了nz-button
属性,让它在编译之后称为ng-zorro-antd
按钮组件。 - 引入
AppComponent
组件。 - 注意引入表单相关依赖,做表单校验等会用到。
/src/app/components/login/login.components.html
登陆的 html
部分只列出表单相关代码。
...
<form nz-form name="form" [formGroup]="validateForm" (ngSubmit)="onSubmit()">
<nz-form-item>
<nz-form-label [nzSpan]="4">用户名</nz-form-label>
<nz-form-control
nzHasFeedback
[nzSpan]="20"
nzErrorTip="请输入用户名"
>
<nz-input-group [nzSuffix]="suffixUsername">
<input
nz-input
placeholder="请输入用户名"
name="username"
formControlName="username"
required
/>
</nz-input-group>
<ng-template #suffixUsername>
<i
nz-icon
class="ant-input-clear-icon"
nzTheme="fill"
nzType="close-circle"
*ngIf="validateForm.controls.username.value.length>0"
(click)="validateForm.controls.username.setValue('')"
></i>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="4">密 码</nz-form-label>
<nz-form-control
nzHasFeedback
[nzSpan]="20"
nzErrorTip="请输入密码"
>
<nz-input-group [nzSuffix]="suffixPassword">
<input
nz-input
name="password"
formControlName="password"
[type]="passwordVisible ? 'text' : 'password'"
placeholder="请输入密码"
required
/>
</nz-input-group>
<ng-template #suffixPassword>
<i
nz-icon
class="ant-input-clear-icon"
nzTheme="fill"
nzType="close-circle"
*ngIf="validateForm.controls.password.value.length>0"
(click)="validateForm.controls.password.setValue('')"
></i>
<i
nz-icon
[nzType]="passwordVisible ? 'eye-invisible' : 'eye'"
(click)="passwordVisible = !passwordVisible"
></i>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzSpan]="20" [nzOffset]="4">
<div nz-row class="login-form-margin">
<div nz-col [nzSpan]="12">
<label nz-checkbox formControlName="remember">
<span>记住我</span>
</label>
</div>
<div nz-col [nzSpan]="12" style="text-align: right;">
<a class="login-form-forgot">忘记密码?</a>
</div>
</div>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzSpan]="24" [nzOffset]="0" style="text-align: center;">
<button
type="submit"
nz-button
style="width: 100px;"
nzType="primary"
ng-disabled="form.$invalid"
>登录</button>
</nz-form-control>
</nz-form-item>
</form>
...
- 表单的
[formGroup]="validateForm"
属性绑定验证对象。 - 表单的
(ngSubmit)="onSubmit()"
属性绑定表单提交事件。 - 输入控件的
formControlName
属性绑定对应的控件名。
/src/app/components/login/login.components.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NzMessageService } from 'ng-zorro-antd/message';
@Component({
selector: 'app-component',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
constructor(
public login: FormBuilder,
private message: NzMessageService
) {}
public validateForm!: FormGroup;
public passwordVisible:Boolean = false;
// 提交表单
onSubmit():void{
// 更新表单未通过验证的控件高亮显示
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
// 如果验证通过
if(this.validateForm.status=='INVALID'){
this.message.create('warning', '请填写用户名和密码');
return;
}
// 如果验证通过
if(this.validateForm.status=='VALID'){
let { username, password } = this.validateForm.value;
if( username == 'admin' && password == '123456' ){
this.message.create('success', '登录成功');
}else{
this.message.create('error', '用户名密码错误');
}
}
}
// 初始化
ngOnInit(): void {
this.validateForm = this.login.group({
username: ['', [Validators.required]],
password: ['', [Validators.required]],
remember: [true]
});
}
}
-
ngOnInit()
是组件生命周期的一种,Angular
会在首次检查完组件或指令的输入属性后,紧接着调用它。这里的业务逻辑是初始化验证表单的内容。 -
onSubmit()
提交表单的逻辑。首先验证实现了FormGroup
接口的表单。高亮化未通过验证的组件(用户名和密码只做了非空验证)。然后验证是否登陆成功,做对应处理。