Angular 5点击按钮时Spinner加载效果无效问题求助
解决Angular 5中点击按钮Spinner不显示的问题
我看了你的代码,问题主要出在loading状态的管理和异步操作的处理上,下面一步步帮你修复:
问题分析
- 组件的loading是私有变量:你在
LoginComponent里声明了private loading: boolean;,Angular模板无法访问私有属性,所以*ngIf="loading"永远不会生效。 - 异步操作的时序错误:你在调用
this.userSrv.login()后立刻把this.loading = false,但API请求是异步的,这会导致loading刚设为true就马上变回false,Spinner根本来不及显示。 - 组件和Service的loading状态不关联:Service里自己维护了一个
loading变量,但组件模板用的是组件自己的,两者没有联动,所以Service里的loading变化不会反映到按钮上。
修复步骤
1. 修正组件的loading变量权限与登录逻辑
把组件里的loading改成public,同时修复判断语法、调整异步操作的loading控制:
export class LoginComponent implements OnInit { // 改成public,让模板可以直接访问 public loading: boolean = false; // ...其他代码 login() { // 修复判断语法:用&&同时校验邮箱和密码 if (this.user.email && this.user.password) { this.loading = true; // 订阅Service返回的Observable,在回调中更新loading this.userSrv.login(this.user.email, this.user.password) .subscribe( (data) => { this.loading = false; if (data.token) { window.location.href = '/'; } else { this.router.navigateByUrl('/login'); } }, (error) => { this.loading = false; this.router.navigateByUrl('/login'); } ); } } }
2. 修改Service的login方法,返回Observable
不要在Service里直接subscribe,而是把Observable返回给组件,让组件统一控制loading状态:
@Injectable() export class UserService { private loginUrl = this.globals.LOGIN_URL; private loggedIn = false; constructor(private http: Http, private router: Router, private globals: Globals) { } login(email: string, password: string): Observable<any> { let headers = new Headers(); headers.append('Content-Type', 'application/json'); return this.http.post( this.loginUrl, JSON.stringify({ email, password }), { headers } ).map(res => res.json()); // 提前处理返回的JSON数据,传给组件 } }
3. 模板代码保持不变(已正确)
你的模板逻辑没问题,只要组件的loading能被正常访问,就能显示Spinner:
<button type="submit" class="btn btn-accent btn-block btn-flat b-r-10" style="background: #FF473A;"> Sign In <i class="fa fa-spinner fa-spin" *ngIf="loading"></i> </button>
额外优化建议
可以用RxJS的finalize操作符统一处理loading重置,避免在成功/失败回调中重复写代码:
// 先导入操作符 import 'rxjs/add/operator/finalize'; // 组件的login函数中 this.userSrv.login(this.user.email, this.user.password) .finalize(() => this.loading = false) // 请求完成(无论成功/失败)都会执行 .subscribe( (data) => { data.token ? window.location.href = '/' : this.router.navigateByUrl('/login'); }, () => { this.router.navigateByUrl('/login'); } );
这样修改后,点击按钮时loading会设为true,Spinner持续显示直到API请求完成,就能实现你想要的加载效果了。
内容的提问来源于stack exchange,提问作者CE0
相关产品推荐
相关产品推荐

