Javascript Google Sheets插件:使用Google应用程序脚本将匿名/动态功能设置为菜单
我想在Google sheets插件中为动态菜单设置动态功能。我正在使用以下代码:Javascript Google Sheets插件:使用Google应用程序脚本将匿名/动态功能设置为菜单,javascript,google-apps-script,google-sheets,Javascript,Google Apps Script,Google Sheets,我想在Google sheets插件中为动态菜单设置动态功能。我正在使用以下代码: function onOpen(e) { var menu = SpreadsheetApp.getUi().createAddonMenu(); for (var i = 0; i < array.length; i++) { const element = array[i]; var functionName = "_" + elemen
function onOpen(e) {
var menu = SpreadsheetApp.getUi().createAddonMenu();
for (var i = 0; i < array.length; i++) {
const element = array[i];
var functionName = "_" + element.name;
var args = element.args;
this[functionName] = dynamicItem(args); //didn't work
//this[functionName] = function () {myopen(args);} //didn't work
//eval("function " + functionName + "() { myopen('" + args + "') }"); //didn't work
menu.addItem(element.name, functionName);
}
menu.addToUi();
}
function dynamicItem(args) {
return function () {
myopen(args);
};
}
开启功能(e){
var menu=SpreadsheetApp.getUi().createAddonMenu();
对于(var i=0;i
单击菜单项时,出现以下异常:
“找不到脚本函数:函数名”
我得到了,和的帮助,但我不知道为什么它对我不起作用
任何帮助都将不胜感激
谢谢。总结:
Google应用程序脚本在一个环境中运行。全局对象中存储的任何内容都不会跨会话进行维护。如果在会话期间向全局对象添加了内容,则该内容在下一次会话运行中不可用。在用户界面实际调用任何函数之前,使用立即调用的函数或全局范围中的调用函数填充全局范围(此
对象)
说明:
..。@bbtv.com先生和Tanaike先生在中提到的解决方案都使用闭包/立即调用函数(IIFE)填充全局范围
要理解这一点,您需要了解何时读取和加载脚本函数名。以下步骤按顺序进行:
中的函数名列表(在此步骤中,没有运行/调用函数,但所有脚本都已完全执行)。这相当于用脚本加载网页:…code.gs…
中
myFunction()
。如果未找到,则抛出错误:脚本函数未找到
此
被永久存储
此[function name]
动态添加菜单项时,在添加函数时要意识到这一点很重要。如果在onOpen
期间添加它,则此
在onOpen
执行期间具有全局范围内的功能,但在onOpen
脚本执行完成后,它立即丢失
function onOpen(){
this['a'] = () => 'a';
SpreadsheetApp.getUi()
.createMenu("Test")
.addItem("Call function a","a")
.addToUi()
}
这将成功地将a
函数添加到Ui
菜单,但请注意,a
仅在执行期间添加到全局此范围。此此
将在执行完成后丢失,并在下次调用任何函数时创建一个新的此
(全局范围)(重复步骤1至5)。因此,当单击按钮时,步骤2创建一个新的this
,并在所有脚本中查找名为a
的函数,但找不到任何函数,因为新创建的this
没有a
(因为onOpen
已声明,但未执行,因此a
这次不会添加到中)
解决方案:
在步骤2期间或之前,您需要将函数添加到全局this
:
function onOpen(){
SpreadsheetApp.getUi()
.createMenu("Test")
.addItem("Call function a","a")
.addToUi()
}
(function IIFE(){
this['a'] = () => 'a';
})();
上面的IIFE函数“每次”截取步骤2,任何函数都被调用。因此,a
总是在步骤3时或之后出现在this
中。在Tanaike的解决方案中,这是通过installFunctions()完成的
在全局范围内。每次调用任何函数时都会执行该函数。注释17中的createMenuFunctions(this);
也是如此
文件摘录:
从
警告:当onOpen(e)函数运行时,将加载整个脚本并执行所有全局语句。这些语句在与onOpen(e)相同的授权模式下执行,如果模式禁止,则会失败。这将阻止onOpen(e)如果发布的加载项未能添加其菜单项,请查看浏览器的JavaScript控制台中是否引发错误,然后检查脚本以查看onOpen(e)函数或全局变量是否调用AuthMode.NONE中不允许的服务
示例脚本:
参考资料:
-
-
-
修改点:
- 在您的脚本中,当打开电子表格时,
onOpen(e)
只运行一次。这样,当选择菜单时,功能就不会安装。我认为这就是您出现问题的原因
- 为了运行动态安装的功能,每次都需要运行创建菜单的脚本。这似乎是由于当前的规范
当上述各点反映到脚本中时,它将变成如下所示
修改脚本:
function installFunctions(){
//样品
var数组=[{name:“sample1”,args:“sample1”},{name:“sample2”,args:“sample2”},{name:“sample3”,args:“sample3”}];
var menu=SpreadsheetApp.getUi().createMenu(“示例”);
对于(var i=0;i/**Runs every time any script function is called*/
(function IIFE(scope) {
'use strict';
scope['options'] = ['a', 'b', 'c']; //pollute current scope
options.forEach(
option =>
(scope[option] = () =>
SpreadsheetApp.getUi().alert(`You clicked option ${option}`))
);
})(this);//pass global scope
function onOpen() {
const testMenu = SpreadsheetApp.getUi().createMenu('Test');
options.forEach(option =>
testMenu.addItem('Call function ' + option, option)
);
testMenu.addToUi();
}
function installFunctions() {
// Samples
var array = [{name: "sample1", args: "sample1"}, {name: "sample2", args: "sample2"}, {name: "sample3", args: "sample3"}];
var menu = SpreadsheetApp.getUi().createMenu("sample");
for (var i = 0; i < array.length; i++) {
const element = array[i];
var functionName = "_" + element.name;
var args = element.args;
this[functionName] = dynamicItem(args);
menu.addItem(element.name, functionName);
}
menu.addToUi();
}
installFunctions(); // This function is run when the Spreadsheet is opened and each menu is selected.
function onOpen() {}
function dynamicItem(args) {
return function () {
Browser.msgBox(args); // Sample script.
// myopen(args);
};
}
function onOpen() {
var ui = SpreadsheetApp.getUi() ;
var menu = ui.createMenu("Choose") ;
Options.forEach( O => menu.addItem(O[0], O[1]) ) ;
menu.addToUi() ;
}
var Options = [] ;
(function() {
let items = ['X','Y','Z'] ;
/* or for example: JSON.parse(PropertiesService.getScriptProperties().getProperty("items")) ; /**/
items.forEach( function(item) {
let funcName = 'Choose$'+item ;
Options.push([item,funcName]) ;
this[funcName] = () => Handle(item) ;
}) ;
})() ;
const Handle = it => console.log("we got %s", it) ;