【问题标题】:How to add a table of contents to a Google Sheets spreadsheet?如何将目录添加到 Google 表格电子表格?
【发布时间】:2020-09-27 15:57:58
【问题描述】:

我正在尝试向 Google 表格添加目录:只是想在文档中包含一个所有表格的列表,作为可点击的链接(获得 150 +床单。)

我让它工作了,但它比我想的要复杂,并且让我对 Google 表格中的自定义函数有疑问。

这就是我所拥有的,当然设置在Tools › Script editor

/**
 * Returns all the document's sheet IDs.
 *
 * @return
 * @customfunction
 */
function tocid() {
  var out = new Array()
  var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
    for (var i=0 ; i<sheets.length ; i++)
      out.push( [ sheets[i].getSheetId() ]
    )
  return out 
}

/**
 * Returns all the document's sheet names.
 *
 * @return
 * @customfunction
 */

function toctitle() {
  var out = new Array()
  var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
    for (var i=0 ; i<sheets.length ; i++)
      out.push( [ sheets[i].getSheetName() ]
    )
  return out 
}

使用每个公式,我得到:

| Sheet_ID   | Sheet_Title       |
|------------|-------------------|
|  349319062 | Table of Contents |
| 1280378086 | many ou much      |
| …          | …                 |

然后我可以使用HYPERLINK 公式获取链接:=hyperlink(concatenate("#gid=",A2), B2)

所以它起作用了。

但是,我尝试一次性完成所有操作,如下所示:

/**
 * Returns a list of all the document's sheets as hyperlinks.
 *
 * @return
 * @customfunction
 *
 * …unfortunately, can't use built-in functions inside of it, it seems. So instead of hyperlinks, it shows the formula for the hyperlinks.
 */
function toclink() {
  var out = new Array()
  var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
    for (var i=0 ; i<sheets.length ; i++)
      out.push( [ "=HYPERLINK(\"#gid=" + sheets[i].getSheetId() + "\", \"" + sheets[i].getName() + "\")" ]
    )
  return out 
}

但是,正如函数的代码 cmets 中所述,它不起作用。

我的问题是:

  1. 您不能在 Google 表格的自定义函数/Google Apps 脚本中使用内置函数这一事实是否真的在任何地方记录? (如果我知道的话,我会节省几个小时的生命。)

  2. 有什么方法可以让自定义函数返回可点击的超链接

我怀疑使用 Range 可能会做到这一点,但我对它们并不满意(而且上述仍然有效的事实使其不那么激励学习)。有没有办法让自定义函数只计算取自另一列的公式?

注意:我不想使用宏。我想在插入新工作表时使用自动更新的解决方案


我意识到这里有一个类似的问题,with a very useful answer。这并不能完全回答我的问题,但比我当前的解决方案更易于使用。

【问题讨论】:

    标签: google-apps-script google-sheets custom-function google-sheets-custom-function


    【解决方案1】:

    Q1:是不是不能使用内置函数...

    如果内置函数是指these,那么不,旨在“在”应用程序“内部”工作的东西肯定不会在用 JavaScript 编写的脚本中可用,除非特别公开为服务/全局变量(它们不是)。

    不过,您可以使用 built-in Google services 的严格子集。请参阅this guide 以确定您可以和不可以。

    最初,我以为您的字面意思是使用 built-in functions,但显然不是这样

    Q2:有什么方法可以让自定义函数返回可点击的超链接?

    不,不使用自定义函数。公式必须通过 setFormula() method 设置,这需要授权并且未列入白名单以与自定义函数一起使用。

    Q3:我想使用一种在插入新工作表时自动更新的解决方案

    答案取决于“插入新工作表时”的含义:

    1. 用户手动插入新工作表:使用可安装的onChangetrigger

    首先,安装一个onChange 触发器,它会在触发时运行名为createTableOfContents 的函数:

    function installOnChange() {
        const ss = SpreadsheetApp.getActiveSpreadsheet();
    
        const builder = ScriptApp
            .newTrigger("createTableOfContents")
            .forSpreadsheet(ss)
            .onChange();
    
        builder.create();
    }
    

    然后,根据您的喜好声明您的createTableOfContents。我创建了一个示例用于演示目的:

    const createTableOfContents = () => {
        const ss = SpreadsheetApp.getActiveSpreadsheet();
        const sheets = ss.getSheets();
    
        const tableOfContents = sheets.map(sheet => {
            return [
                sheet.getSheetId(),
                sheet.getSheetName()
            ];
        });
    
        const withHeaders = [
            ["Sheet Id", "Title"],
            ...tableOfContents
        ];
    
        const [sh] = sheets;
    
        const rng = sh.getRange(1, 1, withHeaders.length, withHeaders[0].length);
    
        rng.setValues(withHeaders).activate();
    
        const formulas = tableOfContents.map(([id,name]) => {
            return [`=HYPERLINK("#gid=${id}","${name}")`];
        });
    
        rng.offset(1, 1, tableOfContents.length, 1).setFormulas(formulas);
    };
    

    请注意,该示例不处理由于工作表删除而导致的范围缩小,但您可以从此处获取:

    1. 通过脚本插入工作表:从插入工作表的函数中运行 createTableOfContents

    我不想使用宏

    其他答案提供了什么is not a marco。宏是用 Google Apps 脚本编写的函数子集,必须在清单中声明并通过键盘快捷键调用。

    参考文献

    1. setFormulas()reference
    2. offset()reference

    建议归功于 TheMaster:

    您可以使用内置服务中的setRichTextValues() 方法和RichTextValueBuilder 类,而不是设置HYPERLINK 公式。所需的更改很小:

    const links = tableOfContents.map(([id,name]) => {
      const value = SpreadsheetApp.newRichTextValue();
    
      return [value
        .setText(name)
        .setLinkUrl(`#gid=${id}`)
        .build()];
    });
    
    rng.offset(1, 1, tableOfContents.length, 1).setRichTextValues(links);
    

    【讨论】:

    • 我想补充一点,您也可以使用富文本类直接设置链接。
    • @TheMaster - 同意,谢谢你的建议 - 更新了答案以包含一个关于如何使用它的示例
    【解决方案2】:

    有很多路要走,还有很多你可能想要的不同的东西。

    function tableOfContents() {
      const ss=SpreadsheetApp.getActive();
      let sh=ss.getSheetByName('Table Of Contents');
      if(sh) {
        ss.deleteSheet(sh);
        SpreadsheetApp.flush();
      }
      sh=ss.insertSheet('Table of Contents',0);
      sh.clear();  
      let c=[["Table of Contents","","",""],["Item","Name","Link","Hidden"]];
      let shts=ss.getSheets();
      shts.forEach(function(sh,i){
        c.push([i+1,sh.getName(),sh.isSheetHidden()?"":Utilities.formatString('=HYPERLINK("\#gid=%s\","Link")',sh.getSheetId()),sh.isSheetHidden()?"Yes":""]);
      })
      sh.getRange(1,1,c.length,c[0].length).setValues(c).setHorizontalAlignment("center").setFontSize(10);
      sh.getRange(1,1,1,c[0].length).mergeAcross().setFontWeight("bold").setFontSize(12).setBorder(false,false,true,false,false,false);
      sh.getRange(2,1,1,c[0].length).setFontWeight("bold").setFontSize(8).setBorder(true,true,true,true,true,true);
    }
    

    【讨论】:

    • 这么一个宏。但这并不是那么方便,因为每次更新工作表时都需要运行宏。相反,自定义函数将在插入新工作表时自动更新其输出。
    • 自定义函数有很多限制,请查看guidelines。您不能插入带有自定义功能的工作表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-11
    • 2016-12-28
    • 1970-01-01
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多