Angular 5中如何在普通JS文件的Ajax请求中调用ngx-toastr?
嘿,作为Angular 5新手遇到这种跨TS和普通JS文件调用Toastr的问题太正常了!我给你两个实用的解决方案,其中第一个是Angular官方推荐的最佳实践,第二个适合你没法修改现有JS文件的场景:
方案1:用Angular HttpClient + 拦截器(强烈推荐)
这是最符合Angular架构的做法,能全局统一处理所有HTTP请求的成功/失败通知,不管请求是在TS组件还是服务里发起的,甚至能帮你把现有JS里的AJAX慢慢迁移到Angular的规范里。
具体步骤:
写一个HTTP拦截器
拦截器能捕获所有HttpClient发起的请求和响应,我们可以在这里自动调用Toastr:import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpResponse, HttpErrorResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; import { ToastrService } from 'ngx-toastr'; @Injectable() export class HttpNotificationInterceptor implements HttpInterceptor { constructor(private toastr: ToastrService) {} intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { return next.handle(request).pipe( tap({ next: (event) => { // 处理成功响应 if (event instanceof HttpResponse && event.status === 200) { // 你可以通过自定义Header来控制是否显示成功提示,灵活度很高 const showSuccess = request.headers.get('showSuccess'); if (showSuccess) { this.toastr.success('请求搞定啦!', '成功'); } } }, error: (error) => { // 处理错误响应 if (error instanceof HttpErrorResponse) { this.toastr.error(error.message || '请求失败啦,稍后再试试?', '出错了'); } } }) ); } }在AppModule里注册这个拦截器
打开app.module.ts,把拦截器加到providers数组里:import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { HttpNotificationInterceptor } from './http-notification.interceptor'; @NgModule({ ... providers: [ { provide: HTTP_INTERCEPTORS, useClass: HttpNotificationInterceptor, multi: true, deps: [ToastrService] } ], ... }) export class AppModule { }发起请求时控制提示
以后在TS里用HttpClient发请求时,只要加个自定义Header就能触发成功提示:import { HttpClient, HttpHeaders } from '@angular/common/http'; constructor(private http: HttpClient) {} fetchData() { const headers = new HttpHeaders().set('showSuccess', 'true'); this.http.get('/api/your-data', { headers }).subscribe(); }
如果你的普通JS文件里的AJAX是原生XMLHttpRequest或fetch,这种方式没法拦截,那可以试试方案二。
方案2:把ToastrService暴露到全局window对象
这种方式能让普通JS直接调用Toastr,但说实话这不是Angular的推荐做法——因为会打破依赖注入的封装,不过适合你没法重构现有JS文件的紧急场景。
具体步骤:
在根组件把Toastr挂到window上
打开AppComponent,先声明全局window的类型,再把ToastrService挂载上去:import { Component } from '@angular/core'; import { ToastrService } from 'ngx-toastr'; // 声明全局window的类型,避免TS报错 declare global { interface Window { toastrService: ToastrService; } } @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { constructor(private toastr: ToastrService) { // 把服务暴露到全局,让JS能访问 window.toastrService = this.toastr; } }在普通JS文件里直接调用
现在你的JS文件里就能直接用全局的toastrService了:// 比如AJAX成功后的回调 function onAjaxSuccess() { // 先判断一下,避免Angular还没初始化就调用报错 if (window.toastrService) { window.toastrService.success('Alert works'); } } // 错误回调 function onAjaxError() { if (window.toastrService) { window.toastrService.error('请求失败了'); } }
小提醒:
- 一定要确保Angular初始化完成后再调用JS里的方法,不然
window.toastrService可能还没赋值哦! - 这种方式尽量少用,能重构JS为Angular服务的话最好还是重构,代码会更易维护。
额外建议
如果你的普通JS文件可以修改,强烈建议把它改成Angular服务(用TS写),这样就能正常注入ToastrService,完全遵循Angular的依赖注入模式,后续维护起来也省心多啦!
内容的提问来源于stack exchange,提问作者Pedro

