如何在 Angular 2 / Typescript 中声明全局变量? [关闭]
Posted
技术标签:
【中文标题】如何在 Angular 2 / Typescript 中声明全局变量? [关闭]【英文标题】:How can I declare a global variable in Angular 2 / Typescript? [closed] 【发布时间】:2016-07-09 14:28:53 【问题描述】:我希望在Angular 2
中以Typescript
语言在任何地方都可以访问一些变量。我应该怎么做呢?
【问题讨论】:
如果它们是静态变量,则无需使用服务。只需在某个文件中添加一个变量,然后在需要它的任何地方导入它。 不幸的是 Angular2 在运行时出现异常,说Uncaught ReferenceError: Settings is not defined
。具有公共静态变量的类Settings
设置为导出并已导入它使用的位置。
我知道这篇文章很旧并且有很多有效的答案。但就像埃里克提到的那样。如果它是您想要声明并在整个应用程序中访问的简单值,您可以创建一个类并使用静态属性导出该类。静态变量与一个类而不是类的实例相关联。您可以导入该类,并将能够从 class.directly 访问该属性。
【参考方案1】:
共享服务是最好的方法
export class SharedService
globalVar:string;
但是您在注册它时需要非常小心,以便能够为整个应用程序共享单个实例。您需要在注册应用程序时定义它:
bootstrap(AppComponent, [SharedService]);
但不要在组件的providers
属性中再次定义它:
@Component(
(...)
providers: [ SharedService ], // No
(...)
)
否则将为组件及其子组件创建一个新的服务实例。
你可以看看这个关于依赖注入和分层注入器如何在 Angular 2 中工作的问题:
What's the best way to inject one service into another in angular 2 (Beta)?您应该注意到,您还可以在服务中定义Observable
属性,以便在您的全局属性更改时通知您的应用程序的某些部分:
export class SharedService
globalVar:string;
globalVarUpdate:Observable<string>;
globalVarObserver:Observer;
constructor()
this.globalVarUpdate = Observable.create((observer:Observer) =>
this.globalVarObserver = observer;
);
updateGlobalVar(newValue:string)
this.globalVar = newValue;
this.globalVarObserver.next(this.globalVar);
查看这个问题了解更多详情:
Delegation: EventEmitter or Observable in Angular【讨论】:
看来这个是不同的。似乎@Rat2000 认为我们的答案是错误的。我通常将这个决定留给其他人,而不是提供竞争性答案的人,但如果他确信我们的答案是错误的,那么我认为这是有效的。他在对我的回答的评论中链接到的文档提到它不受欢迎,但我没有看到任何缺点,并且文档中的论点非常薄弱。将提供程序添加到引导程序也很常见。无论如何,这个论点的目的是什么。那么HTTP_PROVIDERS
和类似的呢,它们也不应该添加到bootstrap()
吗?
是的,我刚刚阅读了文档中的参数和部分。老实说,我真的不明白为什么医生不鼓励它。它是一种定义逻辑拆分的方法吗:引导时Angular2核心特定(路由提供程序,http提供程序)以及应用程序组件注入器中特定于应用程序的内容。也就是说,对于根(在引导时定义),我们只能有一个子注入器(应用程序)。我错过了什么吗?此外,在有关分层注入器的文档中,服务提供者在根注入器中定义;-)
我看到的唯一论点是,保持范围尽可能窄并使用根组件至少在理论上比使用 bootstrap()
稍微窄一些,但实际上这并不重要。我认为将它们列在boostrap()
中会使代码更容易理解。一个组件有提供者、指令、模板。我发现这在没有列出全局提供程序的情况下超载。所以我更喜欢bootstrap()
。
如何引用这样的全局变量?即使在引导服务之后,调用 alert(globalVar)
也会导致错误。
我还没有尝试过,但你会想要这样的东西:alert(this.SharedService.globalVar)【参考方案2】:
这是最简单的解决方案,没有Service
也没有Observer
:
将全局变量放在一个文件中并导出它们。
//
// ===== File globals.ts
//
'use strict';
export const sep='/';
export const version: string="22.2.2";
要在另一个文件中使用全局变量,请使用 import
语句:
import * as myGlobals from 'globals';
例子:
//
// ===== File heroes.component.ts
//
import Component, OnInit from 'angular2/core';
import Router from 'angular2/router';
import HeroService from './hero.service';
import HeroDetailComponent from './hero-detail.component';
import Hero from './hero';
import * as myGlobals from 'globals'; //<==== this one (**Updated**)
export class HeroesComponent implements OnInit
public heroes: Hero[];
public selectedHero: Hero;
//
//
// Here we access the global var reference.
//
public helloString: string="hello " + myGlobals.sep + " there";
...
感谢@eric-martinez
【讨论】:
导入语句出错。必须使用import * as globs from 'globals'
你为什么使用“require”而不是 import from ?
我会使用export const
而不是export var
- 你真的想确保不能更改这些全局变量
这样的导入在 TypeScript 中不再有效。请更新您的答案。正确的是:import * as myGlobals from 'globals'
import * as myGlobals from './path/to/globals';
【参考方案3】:
我就是这么用的:
global.ts
export var server: string = 'http://localhost:4200/';
export var var2: number = 2;
export var var3: string = 'var3';
要使用它,只需像这样导入:
import Injectable from '@angular/core';
import Http, Headers, RequestOptions from '@angular/http';
import Observable from 'rxjs/Rx';
import * as glob from '../shared/global'; //<== HERE
@Injectable()
export class AuthService
private AuhtorizationServer = glob.server
编辑: 按照建议删除了前缀“_”。
【讨论】:
不要使用“_”作为私有属性的前缀。github.com/Microsoft/TypeScript/wiki/Coding-guidelines【参考方案4】:参见例如Angular 2 - Implementation of shared services
@Injectable()
export class MyGlobals
readonly myConfigValue:string = 'abc';
@NgModule(
providers: [MyGlobals],
...
)
class MyComponent
constructor(private myGlobals:MyGlobals)
console.log(myGlobals.myConfigValue);
或提供个别值
@NgModule(
providers: [provide: 'myConfigValue', useValue: 'abc'],
...
)
class MyComponent
constructor(@Inject('myConfigValue') private myConfigValue:string)
console.log(myConfigValue);
【讨论】:
自从 Angular2 beta 7(我认为)你不应该直接在根组件(又名引导程序)中注册你的服务。但是,如果您想覆盖应用程序中的某些内容,您可以在那里注入特定的提供程序。 不确定你的意思。当然你可以在bootstrap()
注册一个服务。 bootstrap()
和根组件是两个不同的东西。当您调用bootstrap(AppComponent, [MyService])
时,您在boostrap()
中注册服务,而AppComponent
是根组件。文档在某处提到它更喜欢在根组件providers: ['MyService']
中注册提供程序(服务),但我还没有找到任何支持或反对bootstrap()
或根组件的论据。
您可以在 Angular 2guide 部分依赖注入(angular.io/docs/ts/latest/guide/dependency-injection.html)中找到您的论点。就像他们说的那样,您可以做到,但不鼓励这样做。这位用户正在寻求最好的方式来注入一些东西,显然你的解决方案并不正确。 @ThierryTemplier 也是如此
我认为 Angular 文档中更重要的引用是“引导提供程序选项旨在配置和覆盖 Angular 自己的预注册服务,例如其路由支持。”我自己很少将服务放在引导程序中,我很高兴看到文档现在建议这样做。
别忘了导出类【参考方案5】:
我也喜欢@supercobra 的解决方案。 我只是想稍微改进一下。如果你导出一个包含所有常量的对象,你可以简单地使用 es6 import 模块而不使用 require。
我还使用 Object.freeze 使属性成为真正的常量。如果您对该主题感兴趣,可以阅读此post。
// global.ts
export const GlobalVariable = Object.freeze(
BASE_API_URL: 'http://example.com/',
//... more of your variables
);
使用 import 引用模块。
//anotherfile.ts that refers to global constants
import GlobalVariable from './path/global';
export class HeroService
private baseApiUrl = GlobalVariable.BASE_API_URL;
//... more code
【讨论】:
这对我来说是最好的解决方案,因为 (1) 它是最简单的代码,并且 (2) 它不需要您将一些该死的服务注入到您想要的每个组件或位置使用它,也不需要你在@NgModule 中注册它。我一生都无法弄清楚为什么有必要创建一个 Angular 2 服务来执行此操作,但也许我忽略了一些东西?我现在正在使用这个很棒的解决方案,但请告诉我为什么这里其他更复杂的答案更好? 您的 GlobalVariable 不是变量。它是一个常数。 @PriyaR LOL,是的,你是对的。我认为这个问题的主要目标是有一种安全的方式来全局访问一些值,所以我即兴创作。否则,请随意将 const 更改为 var,您将得到您的变量。 Object.freeze 的缺点是没有输入值。无论如何,从我的角度来看,将值包装在一个类中是一个更好的设计。所以我们必须在类型化属性和真正的常量之间做出选择。 如何在另一个组件中设置 GlobalVariable.BASE_API_URL..?【参考方案6】:恕我直言,对于 Angular2 (v2.2.3),最好的方法是添加包含全局变量的服务,并将它们注入到组件中,而 @Component
注释内没有 providers
标记。通过这种方式,您可以在组件之间共享信息。
拥有全局变量的示例服务:
import Injectable from '@angular/core'
@Injectable()
export class SomeSharedService
public globalVar = '';
更新全局变量值的示例组件:
import SomeSharedService from '../services/index';
@Component(
templateUrl: '...'
)
export class UpdatingComponent
constructor(private someSharedService: SomeSharedService)
updateValue()
this.someSharedService.globalVar = 'updated value';
读取全局变量值的示例组件:
import SomeSharedService from '../services/index';
@Component(
templateUrl: '...'
)
export class ReadingComponent
constructor(private someSharedService: SomeSharedService)
readValue()
let valueReadOut = this.someSharedService.globalVar;
// do something with the value read out
请注意,
providers: [ SomeSharedService ]
不应不添加到您的@Component
注释中。通过不添加此行注入将始终为您提供SomeSharedService
的相同实例。如果您添加该行,则会注入一个新创建的实例。
【讨论】:
但是没有添加提供者行,我得到了这样的错误:Unhandled Promise rejection: No provider for SomeSharedService
我明白了。我应该在父模块文件中添加providers: [SomeSharedService]
。谢谢。
这在我们延迟加载模块时不起作用。【参考方案7】:
我认为最好的方法是在整个应用程序中通过将对象导出和导入到所需的位置来共享具有全局变量的对象。
首先创建一个新的 .ts 文件,例如 globals.ts 并声明一个对象。我给了它一个 Object 类型,但你也可以使用 any type or
export let globalVariables: Object =
version: '1.3.3.7',
author: '0x1ad2',
everything: 42
;
然后导入
import globalVariables from "path/to/your/globals.ts"
并使用它
console.log(globalVariables);
【讨论】:
【参考方案8】:在 app/globals.ts 中创建 Globals 类:
import Injectable from '@angular/core';
Injectable()
export class Globals
VAR1 = 'value1';
VAR2 = 'value2';
在您的组件中:
import Globals from './globals';
@Component(
selector: 'my-app',
providers: [ Globals ],
template: `<h1>My Component globals.VAR1<h1/>`
)
export class AppComponent
constructor(private globals: Globals)
注意:您可以将 Globals 服务提供者直接添加到模块而不是组件中,并且您不需要将作为提供者添加到该模块中的每个组件。
@NgModule(
imports: [...],
declarations: [...],
providers: [ Globals ],
bootstrap: [ AppComponent ]
)
export class AppModule
【讨论】:
这是最好的答案,因为它提供了一种更便携的方法,而不是必须将服务添加到应用程序中的每个组件。谢谢! 代码正在运行。但请注意,注入类Globals
并将其添加到providers: [ ... ]
意味着您不能更改一个组件内的值,然后再请求第二个组件内的更新值。每次注入 Globals
时,它都是一个新实例。如果你想改变这种行为,只需NOT添加Globals
作为提供者。
只是一个注释,应该是@Injectable()
【参考方案9】:
我喜欢@supercobra 的回答,但我会使用 const 关键字,因为它在 ES6 中已经可用:
//
// ===== File globals.ts
//
'use strict';
export const sep='/';
export const version: string="22.2.2";
【讨论】:
【参考方案10】:我不知道最好的方法,但是如果你想在组件内部定义一个全局变量,最简单的方法是使用window
变量这样写:
window.GlobalVariable = "what ever!"
您不需要将它传递给引导程序或将其导入其他地方,并且它对所有 JS(不仅是 Angular 2 组件)全局可访问。
【讨论】:
我会说这是最糟糕的方式。使用静态变量并不复杂,但也没有那么难看;-) 我同意这很难管理。然而,我最终在开发中使用它们,直到我找到我想要投入生产的东西。在静态变量中,您必须在要使用的任何地方一次又一次地导入它们,除了有一个案例我正在使用 Angular 组件中的 jquery 随时随地生成我的视图 - 没有模板,并使用静态将事件添加到生成的 DOM变量是痛苦。 另外,它不是静态的,你可以从任何地方改变值! 它还会破坏服务器端渲染。远离直接操作窗口或文档。 同意。但我个人在生活中不遵循任何准则(如果我能做得更好的话)。以上是关于如何在 Angular 2 / Typescript 中声明全局变量? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
“如何在我的项目中匹配 typescript 版本,因为它显示错误“需要 typescript@>=2.7.0 <2.8.0”
Springboot + mybatis + React+redux+React-router+antd+Typescript: React+Typescrip项目的搭建