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


10

我有两个使用这些版本的Angular项目:

  • 9.0.0-下一个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有什么区别?


我希望我能从悬赏中得到一个答案,我和其他人可以从中得到更好的了解和理解,以及Angular和不同版本的框架中的providerdi如何工作。
lampshade

Answers:


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;
        },
    },
);

非常感谢您的回答。这非常有帮助,将来我将使用这样的解决方案。
lampshade

5

考虑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服务器上也可以执行),因此最好使用返回windowundefined/ 的工厂null,然后在组件中处理undefined/ nullcase。


1
非常感谢您的详细回答。这很有帮助。
lampshade

1
很好!谢谢。我刚刚检查了Angular文档(v8和v9),但没有找到一个使用字符串的示例。:(他们真的应该在文档中对此进行解释!
Zaphoid
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.