我'm writing an Angular2 service in TypeScript that will make use of localstorage. And I want to inject a reference to the browser window object into my service since I don' t想要引用任何全局变量 . 像angular 1.x $window . 我怎么做?
import { Injectable } from '@angular/core';
// This interface is optional, showing how you can add strong typings for custom globals.
// Just use "Window" as the type if you don't have custom global stuff
export interface ICustomWindow extends Window {
__custom_global_stuff: string;
}
function getWindow (): any {
return window;
}
@Injectable()
export class WindowRefService {
get nativeWindow (): ICustomWindow {
return getWindow();
}
}
现在,使用您的根AppModule注册该服务,以便可以在任何地方注入:
import { WindowRefService } from './window-ref.service';
@NgModule({
providers: [
WindowRefService
],
...
})
export class AppModule {}
然后在你需要注入 window 的地方:
import { Component} from '@angular/core';
import { WindowRefService, ICustomWindow } from './window-ref.service';
@Component({ ... })
export default class MyCoolComponent {
private _window: ICustomWindow;
constructor (
windowRef: WindowRefService
) {
this._window = windowRef.nativeWindow;
}
public doThing (): void {
let foo = this._window.XMLHttpRequest;
let bar = this._window.__custom_global_stuff;
}
...
21 回答
你可以在Angular 4上使用NgZone:
它也是一个将
DOCUMENT
标记为可选的好主意 . 根据Angular文档:以下是使用
DOCUMENT
查看浏览器是否支持SVG的示例:这对我来说当前很有用(2018-03,带有AoT的角度5.2,在angular-cli和自定义webpack版本中测试):
首先,创建一个可注入的服务,提供对窗口的引用:
现在,使用您的根AppModule注册该服务,以便可以在任何地方注入:
然后在你需要注入
window
的地方:如果在应用程序中使用这些,也可能希望以类似的方式将
nativeDocument
和其他全局变量添加到此服务中 .编辑:更新了Truchainz建议 . edit2:更新了角度2.1.2 edit3:添加了AoT备注edit4:添加
any
类型解决方法注意编辑5:更新了解决方案以使用WindowRefService修复了我在使用以前的解决方案时使用不同的构建编辑时遇到的错误6:添加示例自定义窗口类型随着角度2.0.0-rc.5的发布,推出了NgModule . 之前的解决方案停止了为我工作 . 这是我做的修复它:
app.module.ts:
在某些组件中:
您也可以使用OpaqueToken而不是字符串'Window'
编辑:
AppModule用于在main.ts中引导您的应用程序,如下所示:
有关NgModule的更多信息,请阅读Angular 2文档:https://angular.io/docs/ts/latest/guide/ngmodule.html
您可以在设置提供程序后注入它:
这是我为你做的服务 . https://gist.github.com/gdi2290/f8a524cdfb1f54f1a59c
你也可以
import {WINDOW, WINDOW_PROVIDERS} from './window-service';
要么
import {WindowRef, WINDOW_PROVIDERS} from './window-service';
为了使它在Angular 2.1.1上工作,我不得不使用字符串
@Inject
窗口然后像这样嘲笑它
在普通的
@NgModule
中,我这样提供我用OpaqueToken为'Window'字符串:
并用于在Angular 2.0.0-rc-4中的bootstrap中导入
WINDOW_PROVIDERS
.但随着Angular 2.0.0-rc.5的发布,我需要创建一个单独的模块:
并且刚刚在我的主要
app.module.ts
的进口属性中定义在Angular RC4中,以下工作是上述一些答案的组合,在您的根应用程序中添加提供程序:
然后在您的服务等中将它注入构造函数
在@Component声明之前,你也可以这样做,
编译器实际上将允许您现在访问全局窗口变量,因为您将其声明为具有类型any的假定全局变量 .
我建议您不要在应用程序的任何位置访问窗口,您应该创建访问/修改所需窗口属性的服务(并在组件中注入这些服务)以限制您可以对窗口执行的操作,而不必让他们修改整个窗口对象 .
截至今天(2016年4月),上一个解决方案中的代码不起作用,我认为可以将窗口直接注入App.ts,然后将所需的值收集到服务中以便在App中进行全局访问,但是如果您更喜欢创建和注入自己的服务,那么更简单的解决方案就是这样 .
https://gist.github.com/WilldelaVega777/9afcbd6cc661f4107c2b74dd6090cebf
Angular 4引入了InjectToken,它们还为文档创建了一个名为DOCUMENT的令牌 . 我认为这是官方解决方案,它适用于AoT .
我使用相同的逻辑来创建一个名为ngx-window-token的小型库,以防止一遍又一遍地执行此操作 .
我已经在其他项目中使用它并在没有问题的情况下在AoT中构建 .
以下是我在other package中的使用方法
这是plunker
在你的模块中
imports: [ BrowserModule, WindowTokenModule ]
在您的组件中constructor(@Inject(WINDOW) _window) { }
有机会通过文档直接访问窗口对象
您可以从注入的文档中获取窗口 .
我知道问题是如何将窗口对象注入一个组件,但你这样做只是为了到达localStorage . 如果你真的只想要localStorage,为什么不使用一个只暴露它的服务,比如h5webstorage . 然后,您的组件将描述其真正的依赖关系,使您的代码更具可读性 .
这是我发现使用Angular 4 AOT时最短/最干净的答案
资料来源:https://github.com/angular/angular/issues/12631#issuecomment-274260009
这足够了
并做
让AOT高兴
@maxisam感谢ngx-window-token . 我做了类似的事情,但转到你的 . 这是我收听窗口调整大小事件和通知订阅者的服务 .
短而甜美,充满魅力 .
在整个应用程序中访问全局变量时,通过DI(依赖注入)获取窗口对象不是一个好主意 .
但是如果你不想使用window对象,那么你也可以使用
self
关键字,它也指向window对象 .伙计们,保持简单!
实际上,访问窗口对象非常简单,这是我的基本组件,我测试了它的工作原理