问题一:如何援用公有库
起初认为既然 node_modules
是用来寄存装置的包的,那么间接把 @yunzhi
放进 node_modules
里就能够了。
尝试之后发现,尽管能够应用库中的函数,然而当间接援用函数时零碎不主动援用 @yunzhi
,须要人工手动引入。
询问之后发现只须要依据援用的文件名在 package.json
中引入相应依赖,再从新执行 npm install
即可。
之后又发现 package.json 中次要蕴含以下几种参数
"scripts":{...}
"dependencies":{...}
"devDependencies":{...}
其中 scripts:
定义了一组能够运行的 node 脚本。
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
}
也就是平时用到的 ng s,ng t 等。
dependencies
设置了作为依赖装置的 npm
软件包的列表。
比方:
"@angular/animations": "~12.1.2",
"@angular/common": "~12.1.2",
"@angular/compiler": "~12.1.2",
"@angular/core": "~12.1.2",
"@angular/forms": "~12.1.2",
"@yunzhi/ng-common": "0.0.6",
"@yunzhi/ng-mock-api": "0.0.9",
"@yunzhi/ng-theme": "0.0.8",
"@yunzhi/utils": "0.0.3"
这些都是为咱们的利用理论提供相应性能的依赖,也就是为 MVC 层提供服务的依赖。
devDependencies
设置了作为开发依赖装置的 npm
软件包的列表。
比方:
"karma": "~5.1.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.0.3",
"karma-jasmine": "~4.0.0",
"@angular/cli": "~12.1.2",
"@angular/compiler-cli": "~12.1.2",
"@types/jasmine": "~3.6.0",
"@types/node": "^12.11.1",
"@yunzhi/ng-router-testing": "0.0.2",
这些依赖都是在开发时用于测试时所须要的依赖,理论产品中用户并不会用到这些依赖。
晓得了这些当前对于如何更改 angular 版本也就变得很简略,咱们只须要改变带有 @angular 的依赖的版本即可。
问题二:在增加 mockApi 时遇到的问题
对于目前的应用来说只须要增加 qpis.ts
, api.testing.modules
, api.demo.modules
。
其中 apis.ts
也就是一个蕴含有咱们所要用到的 API 的数组。
export const apis = [
UserApi,
LogApi,
ClientApi
];
api.demo.module
用于 ng s 下脱离后盾跑 demoapi.testing.module
用于进行单元测试。
providers: [
{provide: HTTP_INTERCEPTORS, multi: true, useClass: MockApiTestingInterceptor.forRoot(apis)
}]
这是 api.testing 中的次要内容,通过 MockApiTestingInterceptor
的forRoot
办法提供了 HTTP_INTERCEPTORS
拦截器服务。
Angular 在发动 Http 申请时,会查问以后模块是否有 HTTP_INTERCEPTORS 的提供者,如果有则会应用该提供者对申请进行拦挡。
应用 multi: true
来表时以后提供者为多个具备这种能力的一个(应用该计划保障了能够定义多个拦截器)。
static forRoot(mockApis: Type<MockApiInterface>[]): Type<HttpInterceptor>;
这是 MockApiTestingInterceptor
中的 forRoot
办法,接管一个 API 数组,返回一个HttpInterceptor
。
如图便是 MockApi 的机制
返还了 HTTP_INTERCEPTORS
拦截器服务,拦挡到申请后就会依据 forRoot
办法中的 api
数组寻找相应的api
.
Api 大抵格局
export class XxxApi implements MockApiInterface {
protected url = 'xxx'
getInjectors(): ApiInjector[] {
return [{
method: '',
url: '',
result: (urlMatches: string[], options: {params: HttpParams;}){}}]
}
}
其中 urlMatches 为申请 URL 的相干信息,options 包含了承受的参数等信息。
至此,便能够实现拦挡申请并返回模仿数据的性能。
这是就又呈现了一个问题,为什么要在 ng s 中模仿返回数据不能像 ng t 中一样只增加一个 MockApiTestingInterceptor
提供的拦截器
于是我尝试着在 app.modules 中援用 ApiTestingModule
不援用ApiDemoModule
,测试后发现呈现了这样的报错 ——援用谬误:beforeAll 没有被定义。
main.js:1 Uncaught ReferenceError: beforeAll is not defined
ApiDemoModule:
providers: [
{provide: HTTP_INTERCEPTORS, multi: true, useClass: LoadingInterceptor},
{provide: HTTP_INTERCEPTORS, multi: true, useClass: MockApiInterceptor.forRoot(apis)
}]
它比 ApiTestingModule 多了一个 LoadingInterceptor
拦截器:
export class LoadingInterceptor implements HttpInterceptor {public static loadingSubject = new Subject<boolean>();
public static loading$ = LoadingInterceptor.loadingSubject.asObservable();
public static ignoreKey = 'loading-ignore';
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {if (req.params.has(LoadingInterceptor.ignoreKey)) {return next.handle(req);
} else {LoadingInterceptor.loadingSubject.next(true);
return next.handle(req).pipe(finalize(() => LoadingInterceptor.loadingSubject.next(false)));
}
}
}
其中 Subject 是一个非凡的 Observable,它反对将值传给其余很多的 Observable,
req.params.has(xxx)是用来检索 req.params 中是否含有 xxx, 如果没有则返回 null,
handel()将 HttpRequest 转换为 HttpEvents 流, 使其传向下一个拦截器
finalize 返回一个 Observable,该 Observable 镜像源 Observable,但当源在实现或出错时终止时将调用指定函数。
之后通过测试在 ng s 中触发的是
return next.handle(req).pipe(finalize(() => LoadingInterceptor.loadingSubject.next(false)));
也就是说如果申请的参数含有 loading-ignore
阐明没有谬误,能够间接传向下一个拦截器,如果不含有则阐明有谬误,须要通过 finalize
管道的解决,返回一个执行时没有谬误的 Observable 给下一个拦截器。