我有两个使用以下版本的Angular项目:
在版本9中,我使用它来提供并注入window
对象:
@NgModule({
providers: [
{
provide: Window,
useValue: window
},
]
})
export class TestComponent implements OnInit {
constructor(@Inject(Window) private window: Window)
}
哪个工作正常。
对版本8采用这种方法会在编译过程中引发警告和错误:
警告:无法解析TestComponent的所有参数……
我使用单引号解决了这个问题,
@NgModule({
providers: [
{
provide: 'Window',
useValue: window
},
]
})
export class TestComponent implements OnInit {
constructor(@Inject('Window') private window: Window)
}
两个版本之间有什么区别?
导致此问题的Angular 8和9有什么区别?
答案 0 :(得分:6)
为了使您的应用程序可以与服务器端渲染一起使用,我建议您不仅使用窗口通过令牌,而且还以SSR友好的方式创建此令牌,而不要完全引用window
。 Angular内置了DOCUMENT
令牌,用于访问document
。这是我为我的项目通过令牌使用window
的想法:
import {DOCUMENT} from '@angular/common';
import {inject, InjectionToken} from '@angular/core';
export const WINDOW = new InjectionToken<Window>(
'An abstraction over global window object',
{
factory: () => {
const {defaultView} = inject(DOCUMENT);
if (!defaultView) {
throw new Error('Window is not available');
}
return defaultView;
},
},
);
答案 1 :(得分:4)
考虑ValueProvider
界面:
export declare interface ValueProvider extends ValueSansProvider {
/**
* An injection token. Typically an instance of `Type` or `InjectionToken`, but can be `any`.
*/
provide: any;
/**
* When true, injector returns an array of instances. This is useful to allow multiple
* providers spread across many files to provide configuration information to a common token.
*/
multi?: boolean;
}
provide
属性的类型为any
。这意味着任何对象(包括Window
构造函数)都可以进入其中。该对象实际上并不重要,只有引用才有意义,以标识应使用哪个提供程序在构造函数中注入参数。
使用本机Window
构造函数作为注入令牌不应被视为一种好习惯。它在编译时失败,因为Window
在浏览器环境中在运行时存在,它也以TypeScript declare
的形式存在,但是Angular 8编译器无法进行静态代码分析来关联Window
提供者和构造函数参数中的Window
,因为Window
的分配是由浏览器完成的,而不是由代码完成的。不确定为什么它可以在Angular 9中使用...
您应该创建自己的表示依赖项提供程序的注入令牌。该注入令牌应为:
'Window'
所做的一样)InjectionToken
。例如export const window = new InjectionToken<Window>('window');
此外,Angular代码应该与平台无关(应该在浏览器和Node.js服务器上也可以执行),因此最好使用返回window
或{{1}的工厂} / undefined
,然后处理组件中的null
/ undefined
情况。