【问题标题】:Using methods for the menu item callbacks in Google Apps Script在 Google Apps 脚本中使用菜单项回调方法
【发布时间】:2026-01-19 20:30:02
【问题描述】:

所以,我正在使用 Google Apps Script 做一个小项目,以便从中添加/导出潜在客户...不那么痛苦。

我打算怎么做?

我计划通过添加一些Actions 菜单来实现这一点,用于导入和导出潜在客户。目前,假定导入的工作表与该脚本绑定到的 Google 工作表具有相同的列。 (我们稍后可以支持一些表格列转换功能,但它可能是我的用例的 YAGNI。)导出的表格将从该表格的列转换为一些简化的、准备发送到邮件的列。

我打算如何编写此代码(或如何编写代码)?

我正在使用 MVVM 设计模式,昨晚一直在为我需要的所有内容编写 MVVM 包装器(牢记 KISS)。

MenuItemViewModels 有一些name,functionNameGoogle Apps Script seem to be looking for。我注意到有一些主要的痛苦限制:Google Apps 脚本需要函数 NAME 并且 它不能是方法

好的,给我看一些代码或gtfo

我有一些SpreadsheetPageViewModel,看起来像这样:

class SpreadsheetPageViewModel extends BaseViewModel {
  init() { 

    
    this.exportVM = new ExportSpreadsheetEditViewModel();
    this.importVM = new ImportSpreadsheetEditViewModel();

    this.menuVM = new MenuViewModel(new MenuModel(),
      [
        'exportLeads', // this is utility function. I want/need to use openExport method
        'importLeads', // this is utility function. I want/need to use openImport method
      ]);


    this.childEditVM = null;
  } 

  openExport() { 
    this.childEditVM = this.exportVM;
    this.childEditVM.view.doShow();
  }

  openImport() { 
    this.childEditVM = this.importVM;
    this.childEditVM.view.doShow();
  }
}

在单击菜单项时生成的模式的业务逻辑将存在于子视图模型中:ExportSpreadsheetEditViewModelImportSpreadsheetEditViewModel

我试图通过这个 hack 绕过限制:

变化

function onOpen(event) { 
  // show the menu here....
  new SpreadsheetPageView().doShow();
}

类似于:

var mainView;

function onOpen(event) { 
  mainView = new SpreadsheetPageView();
  // show the menu here....
  mainView.doShow();
}

然后,在MenuActionUtils.gs 中,沿着mainView 向下爬行,例如:

function exportLeads() { 
  mainView.viewModel.showExport();
}

function importLeads() { 
  mainView.viewModel.showImport();
}

那次黑客攻击的结果是什么?

没有用。为什么?因为当 Google Apps 脚本触发 exportLeads(或 importLeads)时,mainView 不再被定义!!

这是否意味着我必须放弃我的方法? 如何在菜单项的 onClick 中使用主视图/视图模型? 如果失败了,有没有办法使用这种 MVVM 设计模式(以及一些 HTML/React/....)来创建我们的菜单并将其注入?

【问题讨论】:

  • 人们反对并投票关闭这个?!这个问题如何让他们想要这样做?!
  • 这在 SO 中值得一些空间。这篇文章最初总结了这个问题,以至于它阐明了在谷歌脚本应用程序生态系统中开发时事物如何工作和不工作的性质,并特别指出了谷歌的开发人员文档根本没有涵盖的内容:在这个空间中开发时发生的事情是一个微妙而重要的细节,你应该在部署现场之前知道......我的解决方案涉及转换为功能主义,以便映射函数减少数组从谷歌表单元返回到管道并再次输出到用户界面

标签: javascript google-apps-script google-sheets design-patterns mvvm


【解决方案1】:

通过使用 Google Apps 脚本,您无法修改 Google Workspace 编辑器(文档、表单、表格、幻灯片)自定义菜单的外观,换句话说,您无法使用 HTML/React可能会在对话框/侧边栏中使用它们。

关于使用设计模式,您可以使用任何您想要的设计模式,但您应该记住,每次 Google Apps 脚本被事件触发时,整个项目都会被加载,所以如果您需要一些对象在事件之间持续存在,那么您应该找到保存这些对象的地方。

要存储对象,您可能会使用 Google Apps 脚本属性服务和/或缓存服务,但请记住,您应该在保存之前将其转换为 JSON。您也可以使用 Google 电子表格,但这有一些限制,或者您可以通过 Google Apps Script URL Fetch 服务使用外部服务,即 nosql 数据库。

相关

【讨论】:

  • 感谢您的意见!通过对设计进行一些额外的思考,我能够让它发挥作用!
【解决方案2】:

在@Ruben 的帮助下,我得以完成这项工作!

我做了什么

我没有放弃 MVVM/OOP 设计。

相反,我在驱动类上创建了单例静态方法,如下所示:

static GetMainInstance() { 
    if (!this._mainInstance) { 
      this._mainInstance = new this();
    }

    return this._mainInstance;
  }

并使用它而不是直接创建新的驱动器对象。

另外,生成东西是视图的责任,所以我做了一些重构:

PageView.gs我添加了以下方法:

showExport() { 
    this.viewModel.showExport((childVM) => {
      this.editView.viewModel = childVM;
      this.editView.doShow();
    })
  }

  showImport() { 
    this.viewModel.showImport((childVM) => {
      this.editView.viewModel = childVM;
      this.editView.doShow();
    })
  }

PageViewModel.gs 中,我将方法更改为接受onDone 回调:

showExport(onDone) { 
    this.childEditVM = this.exportVM;
    onDone(this.childEditVM);
  }

  showImport(onDone) { 
    this.childEditVM = this.importVM;
    onDone(this.childEditVM);
  }

简单的修复,它的工作原理,同时保持一致!

【讨论】:

  • 谢谢。多年没有编码后,我来到一个仓库工作,其软件基于谷歌表格,并且知道我所知道的关于谷歌脚本的知识让我产生了制作 ui 的想法,可能与你可能处理的数据不同。几次重写,两周后,我完成了几乎所有我能用仿真处理 TDD 的东西,所以只有把它抱进去,而且尽可能地控制它应该是好的。一切正常,但模型的不一致重新生成!出于同样的原因,你来找。你能详细说明你的驱动类是什么意思吗?