To use gapi
and gapi.auth
对于 Angular2,使用 NPM 安装类型脚本定义。
npm install --save @types/gapi
npm install --save @types/gapi.auth2
这将安装两个包,@类型/gapi https://www.npmjs.com/package/@types/gapi and @类型/gapi.auth2 https://www.npmjs.com/package/@types/gapi.auth2 to the node_modules
文件夹并将配置保存在package.json
.
检查你的node_modules
文件夹以检查它们安装是否正确。如果您的 Angular 应用程序名为“main-app”,您应该看到:
main-app/
node_modules/
@types/
gapi/
gapi.auth2/
The 红色药丸和蓝色药丸 https://en.wikipedia.org/wiki/Red_pill_and_blue_pill设想:
- 如果没有提供任何类型编译器选项 https://www.typescriptlang.org/v2/en/tsconfig#types应该不需要显式添加
gapi
or gapi.auth2
to the "types": []
编译器选项在tsconfig.json
because
- 默认情况下所有可见
@types
编译期间包含软件包。
- 包裹在
node_modules/@types
(任何封闭文件夹的)被视为可见。
-
But. If
types
已经指定,则TS配置参考 https://www.typescriptlang.org/v2/en/tsconfig#types说明您必须添加gapi
or gapi.auth2
否则默认情况下将不包含它们。在此场景中,编辑tsconfig.json
包括新的gapi
and gapi.auth2
types:
{
"compilerOptions": {
"types": ["jest", "lodash", "gapi", "gapi.auth2"]
}
}
此时,如果你觉得有足够的动力,你可以阅读Typescript 模块分辨率 https://www.typescriptlang.org/docs/handbook/module-resolution.html,你可以直接跳到Node.js 如何解析模块:
节点将在名为的特殊文件夹中查找您的模块
node_modules
. A node_modules
文件夹可以与
当前文件,或目录链中的更高位置。节点会向上走
目录链,逐一查看node_modules
直到找到
您尝试加载的模块。
因此,您不需要在 Angular2 服务或组件(或者您使用的任何地方)中添加对类型定义的引用gapi
or gapi.auth2
).
但是,如果您确实添加了对gapi
or gapi.auth2
TypeScript 定义,它必须引用.ts
使用安装的文件npm install
(注意,您必须保留///
否则你会得到一个错误):
/// <reference path="../../node_modules/@types/gapi/index.d.ts" />
该路径是相对的,因此您的路径可能会有所不同,具体取决于您所在的位置.ts
文件与您安装 TypeScript 定义的位置相关。
无论您添加显式引用还是使用 TypeScript 的 Node 模块解析机制,您仍然需要在.ts
文件以便 Angular 了解窗口gapi
编译时变量。添加declare var gapi: any;
给你的.ts
文件但做not将其放在类定义中。我把我的放在所有进口的下面:
// You may not have this explicit reference.
/// <reference path="../../node_modules/@types/gapi/index.d.ts" />
import { NgZone, Injectable, Optional } from '@angular/core';
declare var gapi: any;
使用其他 JavaScript 库 in TypeScript 文档 https://www.typescriptlang.org/docs/handbook/namespaces.html值得阅读以了解我们通过所有这些工作得到了什么。
接下来,加载gapi
来自您自己的函数的客户端(可能在 Angular 服务中):
loadClient(): Promise<any> {
return new Promise((resolve, reject) => {
this.zone.run(() => {
gapi.load('client', {
callback: resolve,
onerror: reject,
timeout: 1000, // 5 seconds.
ontimeout: reject
});
});
});
}
这个函数并不简单,原因如下......
首先,请注意我们正在调用间隙负载 https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiloadlibraries-callbackorconfig with a 配置对象而不是一个callback. The GAPI 参考 https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiloadlibraries-callbackorconfig状态可以使用:
- 库完成时调用的回调函数
加载中。
- 封装各种配置参数的对象
对于这个方法。只需要回调即可。
使用配置选项使我们能够reject加载库时的 Promise 超时,或者只是错误。根据我的经验,加载库比初始化它更容易失败——这就是为什么配置对象比回调更好的原因。
其次,我们要包装gapi.load
in
this.zone.run(() => {
// gapi.load
});
NgZone.run 已记录 https://angular.io/api/core/NgZone#run和国家
通过运行函数zone.run
允许您重新进入 Angular 区域
在 Angular 区域之外执行的任务 [...]
这正是我们想要的,因为调用gapi.load
离开角区。忽略这一点可能会导致非常奇怪的结果,并且很难调试。
第三,loadClient()
返回一个已解决的承诺 - 允许调用者选择他们如何处理gapi.load
。例如如果我们的loadClient
方法属于 Angular 服务,apiLoaderServce
,一个组件可以使用ngOnInit
加载gapi
:
ngOnInit(): void {
this.apiLoaderService.loadClient().then(
result => this.apiLoaded = true,
err => this.apiLoaded = false
);
}
Once gapi.load
已被称为,gapi.client
将准备就绪,您应该使用它通过 API 密钥、OAuth 客户端 ID、范围和 API 发现文档来初始化 JavaScript 客户端:
initClient(): Promise<any> {
var API_KEY = // Your API key.
var DISCOVERY_DOC = // Your discovery doc URL.
var initObj = {
'apiKey': API_KEY,
'discoveryDocs': [DISCOVERY_DOC],
};
return new Promise((resolve, reject) => {
this.zone.run(() => {
gapi.client.init(initObj).then(resolve, reject);
});
});
}
注意我们的朋友NgZone.run https://angular.io/api/core/NgZone#run再次使用以确保重新进入角度区域。
在实践中,我添加loadClient()
and initClient()
到 Angular 服务。在高级 Angular 组件(通常位于应用程序组件下方)中,我加载并初始化ngOnInit
:
ngOnInit(): void {
this.apiLoaderService.loadClient().then(
result => {
this.apiLoaded = true;
return this.apiLoaderService.initClient()
},
err => {
this.apiFailed = true;
}
).then(result => {
this.apiReady = true;
}, err => {
this.apiFailed = true;
});
}
最后,您需要将gapi 脚本文件添加到您的文件中。
<html>
<head>
<script src="https://apis.google.com/js/api.js"></script>
您不得使用async
or defer
属性,因为它们会导致 Angular 世界在 gapi 库加载之前进入。
<!-- This will not work. -->
<html>
<head>
<script async defer src="https://apis.google.com/js/api.js"></script>
我之前建议通过加载本地的缩小版副本来保持页面加载速度快加皮图书馆 https://apis.google.com/js/api.js in the /main-app/src/assests
文件夹并导入:
<html>
<head>
<script src="assets/api.js"></script>
但是,我strongly推荐不做这。谷歌可能会更新https://apis.google.com/js/api.js https://apis.google.com/js/api.js你的客户就会崩溃。我已经被这个问题迷惑过两次了。最后最好是从//apis.google.com/js/
并将其保留为阻塞调用。