在Angular 8和9中提供和注入“窗口”与窗口之间有什么区别?

时间:2019-11-15 09:27:42

标签: javascript angular typescript dependency-injection angular8

我有两个使用以下版本的Angular项目:

  • 9.0.0-next.6
  • 8.1.0

在版本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有什么区别?

2 个答案:

答案 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情况。