Angular中如何同步动态<script>标签与组件.ts代码以安全访问全局对象
Angular中动态加载外部JS并安全访问全局对象的方案
一、解决Cannot find name 'google'的类型报错
TypeScript无法识别挂载到window上的全局对象,只需添加全局类型声明:
- 在项目根目录或
src下创建typings.d.ts文件 - 写入以下内容:
declare global { interface Window { google: any; // 若需要更精确的类型,可安装GSI的类型包后替换为具体类型 // google: typeof import('@types/google.accounts'); } } export {};
二、封装动态加载脚本的Promise工具
通过Promise封装脚本加载逻辑,确保脚本加载完成后再执行依赖代码:
// src/utils/script-loader.ts export function loadScript(src: string): Promise<void> { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.async = true; script.defer = true; script.onload = () => resolve(); script.onerror = (err) => reject(new Error(`加载脚本失败:${src},错误信息:${err}`)); document.body.appendChild(script); }); }
三、组件中安全使用全局对象
在组件生命周期钩子中,通过await等待脚本加载完成后,再访问全局对象:
import { Component, OnInit } from '@angular/core'; import { loadScript } from './utils/script-loader'; @Component({ selector: 'app-root', templateUrl: './app.component.html', }) export class AppComponent implements OnInit { async ngOnInit() { try { // 加载Google GSI脚本 await loadScript('https://accounts.google.com/gsi/client'); // 脚本加载完成,安全访问google对象 window.google.accounts.id.initialize({ client_id: '你的Google客户端ID', callback: (response) => { // 处理登录回调逻辑 console.log('登录成功', response); } }); // 渲染登录按钮 window.google.accounts.id.renderButton( document.getElementById('g_id_signin'), { theme: 'outline', size: 'large' } ); } catch (error) { console.error('初始化GSI失败', error); } } }
四、适配angularx-social-login库的场景
若使用angularx-social-login库自动加载脚本但无加载状态回调,可通过监听全局对象的方式等待其加载完成:
// src/utils/wait-for-global.ts export function waitForGlobalObject(objName: string, timeout = 10000): Promise<any> { return new Promise((resolve, reject) => { const checkTimer = setInterval(() => { if (window[objName as keyof Window]) { clearInterval(checkTimer); resolve(window[objName as keyof Window]); } }, 100); setTimeout(() => { clearInterval(checkTimer); reject(new Error(`等待全局对象${objName}超时`)); }, timeout); }); }
在组件中使用:
import { Component, OnInit } from '@angular/core'; import { SocialAuthService } from 'angularx-social-login'; import { waitForGlobalObject } from './utils/wait-for-global'; @Component({ selector: 'app-root', templateUrl: './app.component.html', }) export class AppComponent implements OnInit { constructor(private authService: SocialAuthService) {} async ngOnInit() { try { // 等待google对象加载完成 await waitForGlobalObject('google'); // 此时可安全执行依赖google对象的逻辑,或初始化社交登录相关配置 } catch (error) { console.error('等待Google对象加载超时', error); } } }
内容的提问来源于stack exchange,提问作者chick3n0x07CC
相关产品推荐
相关产品推荐

