You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中如何同步动态<script>标签与组件.ts代码以安全访问全局对象

Angular中动态加载外部JS并安全访问全局对象的方案

一、解决Cannot find name 'google'的类型报错

TypeScript无法识别挂载到window上的全局对象,只需添加全局类型声明:

  1. 在项目根目录或src下创建typings.d.ts文件
  2. 写入以下内容:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 06:05:19