Javascript 什么';提供和注入的区别是什么';窗口';角度8和9中的vs窗口?
我有两个使用这些版本的角度项目:Javascript 什么';提供和注入的区别是什么';窗口';角度8和9中的vs窗口?,javascript,angular,typescript,dependency-injection,angular8,Javascript,Angular,Typescript,Dependency Injection,Angular8,我有两个使用这些版本的角度项目: 9.0.0-next.6 8.1.0 在版本9中,我使用它来提供并注入窗口对象: @NgModule({ providers: [ { provide: Window, useValue: window }, ] }) export class TestComponent implements OnInit { constructor(@Inject(Window) private window: Wi
- 9.0.0-next.6
- 8.1.0
在版本9中,我使用它来提供并注入
窗口
对象:
@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)
}
两种版本之间的区别是什么?
角度8和角度9的差异是什么导致了这种情况?考虑到
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
。这意味着任何对象(包括窗口
构造函数)都可以进入其中。对象实际上并不重要,只有引用重要,可以确定应该使用哪个提供程序在构造函数中注入参数
使用本机窗口
构造函数作为注入令牌不应被视为一种良好做法。它在编译时失败,因为窗口
在运行时存在于浏览器环境中,它也作为类型脚本声明
存在,但Angular 8编译器无法进行静态代码分析,以关联提供程序中的窗口
和构造函数参数中的窗口
,因为窗口的分配是由浏览器完成的,而不是由代码完成的。不知道为什么它在Angular 9中工作
您应该创建自己的表示依赖项提供程序的注入令牌。此注入令牌应为:
- 专用字符串(就像您使用
'Window'
)
- 专用的
注入令牌
。例如export const window=new InjectionToken('window')代码>
此外,角度代码应该是平台无关的(应该可以在浏览器和Node.js服务器上执行),因此最好使用返回窗口
或未定义
/空
的工厂,然后在组件中处理未定义的
/空
情况。为了让您的应用程序能够使用服务器端渲染,我建议您不仅使用window-through令牌,而且以SSR友好的方式创建此令牌,完全不引用window
。Angular具有内置的文档
令牌,用于访问文档
。以下是我的项目通过令牌使用window
的方法:
从'@angular/common'导入{DOCUMENT};
从'@angular/core'导入{injection,InjectionToken};
导出常量窗口=新注入令牌(
“全局窗口对象上的抽象”,
{
工厂:()=>{
const{defaultView}=inject(文档);
如果(!defaultView){
抛出新错误(“窗口不可用”);
}
返回默认视图;
},
},
);
编辑:由于这是人们经常需要的,我们使用此技术创建了一个小型开源库,其中包含全局对象的注入标记,因此您可以使用它:
在Angular Universal中,它有一个用于模拟的姊妹库,可与SSR一起使用:
总的来说,请查看我们的本地API中心:
我希望通过赏金,我能得到一个答案,我和其他人可以从中更好地了解提供者和di在Angular和框架的不同版本中的工作方式。非常感谢您的回答。这是非常有用的,我将来将使用类似的解决方案。@lampshade查看我们创建的这个小库,它有许多全局对象标记,如窗口、导航器、位置等:作为替代,您可以忽略显式错误抛出
并按原样返回defaultView
。因此,消费组件可以检查此.window
是否错误,因此可以轻松跳过与window
相关的逻辑。我从未遇到过不可用的情况,包括SSR。这更像是一个让人满意的打字脚本。非常好!谢谢我只是检查了Angular文档(v8和v9),没有找到一个使用字符串的示例:(他们应该在文档中真正解释这一点!