700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 【Angular实战/网易云】验证码注册

【Angular实战/网易云】验证码注册

时间:2024-05-12 20:46:29

相关推荐

【Angular实战/网易云】验证码注册

一. 模板内容

思路如下:

先让用户输入自己的手机号和密码,然后点击注册按钮跳转到输入验证码的界面。在验证码的界面输入正确的验证码之后,点击注册即可成功注册。

按照这个思路,“输入手机号和密码”视图以及“输入验证码”视图是两个完全不同的视图,需要用两个组件来实现。

但是,当用户输入完验证码以后,我们需要拿着用户之前输入的手机号和验证码发送到后台,看看这个验证码是否正确。

所以我们需要组件之间的数据通信,这个如果要靠非父子组件来实现稍微啰嗦了一点,又要往store里面加入新的内容。所以我们把注册页面和验证码页面当作父子组件,然后通过ng-template的配合*ngIf来判断什么时候显示注册页面,什么时候显示验证码页面

<div class="register modal-content"><div class="modal-wrap" *ngIf="!showCode else code"><form nz-form nzLayout="vertical" [formGroup]="formModal" (ngSubmit)="onSubmit()"><nz-form-item><nz-form-label>手机号</nz-form-label><nz-form-control nzHasFeedback nzErrorTip="请填写正确的手机号"><nz-input-group nzPrefixIcon="mobile"><input type="tel" nz-input placeholder="请输入手机号" formControlName="phone"></nz-input-group></nz-form-control></nz-form-item><nz-form-item><nz-form-label>密码</nz-form-label><nz-form-control nzHasFeedback nzErrorTip="请输入密码"><nz-input-group nzPrefixIcon="lock"><input type="password" nz-input placeholder="请输入密码" formControlName="password"></nz-input-group></nz-form-control></nz-form-item><nz-form-item><nz-form-control><button type="submit" nz-button nzBlock>下一步</button></nz-form-control></nz-form-item></form></div><ng-template #code><div class="modal-wrap"><app-wy-check-code [timing]="timing"[codePass]="codePass"[phone]="formModal.get('phone').value"(onCheckCode)="onCheckCode($event)"(onRegister)="onCheckExist()"(onRepeatSendCode)="sendCode()"></app-wy-check-code></div></ng-template></div><div class="m-footer clearfix"><a (click)="changeType()">&lt; 其它登陆方式</a></div>

二. 发送验证码

可以看到,当我们点击下一步的时候,就应该调用发送验证码的接口了。

除此之外我们还需要改变模板显示的内容,以及要给子组件(也就是验证码组件发送数据)。

总之,我们要做这三件事:

改变当前模板的显示状态,改为显示验证码的组件。由于我们的验证码需要进行60s的倒计时,所以这里注册一个异步事件,进行60s倒计时,然后传递给子组件。

注意我们调用验证码接口,后台是不会给我们返回验证码的。

onSubmit() {if (this.formModal.valid) {this.sendCode();}}sendCode() {this.memberService.sendCaptcha(this.formModal.get('phone').value).subscribe(() => {this.timing = 60;if (!this.showCode) {this.showCode = true;}interval(1000).pipe(take(60)).subscribe(() => {this.timing--;console.log(this.timing);}), error => this.messageService.error(error.message);});}

三. 验证码模板设计

验证码页面的设计说到底也是一个表单,不过中间显示四个验证码稍微复杂一点,我又把他抽出来做了一个组件。

<div class="check-code"><div class="js-mobwrap"><p class="s-fc3">你的手机号<strong class="s-fc1"><span class="js-mob">{{phone}}</span></strong></p><p class="s-fc4">为了安全,我们会给您发送短信验证码</p></div><div class="form"><form nz-form nzLayout="vertical" [formGroup]="formModel" (ngSubmit)="onSubmit()"><nz-form-item><nz-form-control><app-wy-code formControlName="code"></app-wy-code><div class="send clearfix"><span class="err" [hidden]="codePass">验证码错误</span><span class="txt" *ngIf="!showRepeatBtn else repeatBtn">{{timing}}s</span><ng-template #repeatBtn><span class="txt repeat" (click)="onRepeatSendCode.emit()">重新发送</span></ng-template></div></nz-form-control></nz-form-item><nz-form-item><nz-form-control><button nz-button nzType="primary" nzBlock>下一步</button></nz-form-control></nz-form-item></form></div>

app-wy-code组件的内容:

<div class="code-wrap clearfix" #codeWrap><div class="u-word" *ngFor="let item of inputArr; index as i"><input class="item" maxlength="1" /></div></div>

四. 验证码组件逻辑

这里提到的验证码组件逻辑是app-wy-code的逻辑,我们来想想这个4个input要完成什么样的功能。

首先,你每输入一个数字,就会触发下一个input的焦点事件。如果你手动选中一个input,那么该input就会触发焦点事件。不能输入除数字以外的内容,用户按下其他键我们就不相应。

接下来我们来完成这些内容,首先这个app-wy-code是一个angular的表单组件(这样才能和之前的form配合获取值),所以要实现ControlValueAccessor的接口。

export class WyCodeComponent implements OnInit, ControlValueAccessor {// ...setValue(code: string) {this.code = code;this.onChange(code);this.cdr.markForCheck();}writeValue(code: string): void {this.setValue(code);}registerOnChange(fn: any): void {this.onChange = fn;}registerOnTouched(fn: any): void {this.onTouched = fn;}}

另外,我们还要获取到这四个input的DOM,但是我们无法通过#+ViewChild来获得了。而且这些DOM都是通过*ngFor来实现的,所以我们要实现AfterViewInit接口。然后调用getElementsByClassname来获取这四个input的DOM。

ngAfterViewInit(): void {this.inputItems = this.elementRef.nativeElement.getElementsByClassName('item') as HTMLElement[];this.inputItems[0].focus();for (let i = 0; i < this.inputItems.length; ++i) {const item = this.inputItems[i];fromEvent(item, 'keyup').pipe(takeUntil(this.destroy$)).subscribe((event: KeyboardEvent) => this.listenup(event));fromEvent(item, 'click').pipe(takeUntil(this.destroy$)).subscribe(() => this.currentFocusIndex = i);}}

我们直接给这四个组件绑定了相应的keyup和click事件,具体实现如下:

listenup(event: KeyboardEvent) {const target = event.target as HTMLInputElement;const value = target.value;const isBackSpace = event.keyCode === BACKSPACE;if (/\D/.test(value)) {target.value = '';this.result[this.currentFocusIndex] = '';} else if (value) {this.result[this.currentFocusIndex] = value;this.currentFocusIndex = (this.currentFocusIndex + 1) % CODELEN;this.inputItems[this.currentFocusIndex].focus();} else if (isBackSpace) {this.result[this.currentFocusIndex] = '';this.currentFocusIndex = Math.max(this.currentFocusIndex - 1, 0);this.inputItems[this.currentFocusIndex].focus();}this.checkResult(this.result);}private checkResult(result: string[]) {const codeStr = result.join('');this.setValue(codeStr);}

这个代码已经写得非常清楚了,我就不再解释了。

注意当你监听一个事件的同时,也要想办法什么时候停止监听,这里使用destroy$ + OnDestroy接口来实现。

private destroy$ = new Subject();ngOnDestroy(): void {this.destroy$.next();this.destroy$.complete();}

destroy是怎么影响到我们的input的呢?原来是通过takeUtil操作符(见上面代码)

五. 验证验证码和判断用户是否已经注册

RT,我们还需要增加这两个功能。

什么时候发送验证码到服务端?答案是当你输完四个数字的时候。

可以在定义formGroup的时候限定四个数字,这样当你输入完的时候就会触发表单的statusChange事件

constructor(private fb: FormBuilder) {this.formModel = this.fb.group({code: ['', [Validators.required, Validators.pattern(/\d{4}/)]]});const codeControl = this.formModel.get('code');codeControl.statusChanges.subscribe(status => {if (status === 'VALID') {this.onCheckCode.emit(codeControl.value);}});}

这里我直接把验证验证码交给父组件处理了,其实也就是调一个接口,不多BB。

对于判断用户是否存在,只要在onSubmit的时候处理下就行了。

onSubmit() {this.onRegister.emit();}

六. 验证码组件的其它功能

· 隐藏用户的手机信息

利用好typescript的get和set方法,以一个private的属性为中介,输出电话号码。

// Input和Set的组合@Input()set phone(phone: string) {const arr = phone.split('');arr.splice(3, 4, '****');this.phoneHideStr = arr.join('');}get phone() {return this.phoneHideStr;}

· 60s倒计时

这个我们在父组件已经实现过了,只要好好接收就行。

这里重点要讲的其实是60s到的时候我们显示“重新发送”,然后点击这个重

新发送就会真的重新发送

// 每次输入的事件变化就会触发这个OnChanges事件// 每次改变我们就看看是不是要显示对应的按钮ngOnChanges(changes: SimpleChanges): void {if (changes.timing) {this.showRepeatBtn = this.timing <= 0;}}

显然这两个dom的事件都发生了变化,我选择使用*ngIf进行实现:

<span class="txt" *ngIf="!showRepeatBtn else repeatBtn">{{timing}}s</span><ng-template #repeatBtn><span class="txt repeat" (click)="onRepeatSendCode.emit()">重新发送</span></ng-template>

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。