如何将真正实时的 Google 表格电子表格嵌入到网页中?

How do I embed a truly live Google Sheets spreadsheet into a webpage?

我想要的

一个显示真正实时 sheet 的网站(当 sheet 从其他地方更改时立即更新,例如在编辑器中),但居中于屏幕且没有菜单等(例如在 2b)

具体是哪个网站

我所知道的

经过多次 Google 搜索,我找到了两个符合我目标的结果:

1。 Google 没有菜单的工作表编辑器

您可以直接在编辑器中显示 sheet,只需将 ?rm=minimal 添加到 url,如

https://docs.google.com/spreadsheets/d/SPREADSHEET_ID/view?rm=minimal#gid=SHEET_ID

这个

但是

2。其他 URL 东西

当您编辑 URL 并将 /edit... 替换为 /htmlembed/sheet?gid=SHEET_ID 时,如

https://docs.google.com/spreadsheets/u/0/d/SPREADSHEET_ID/htmlembed/sheet?gid=SHEET_ID

这个

可以使用 GScript WebApp 进行扩展:

2b。 GScript 网络应用

(请注意,我使用绿色而不是黑色进行可视化)

在作为 WebApp 发布的 GScript doGet(e) 函数中使用此 URL 允许我进一步自定义它。我只是在原始来源中添加了一个 style-tag 并使用 background-color 以及 flex display 来设置背景和居中内容。这是我的功能,非常容易受到 HTML 注入的影响:

function doGet(e) {
  // Getting spreadsheet app
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  // Getting sheet
  var sheet = ss.getSheetByName("Monitor " + e.parameter.monitor);
  //Return error if specified sheet does not exist
  if (sheet == null)
    return HtmlService.createHtmlOutput("<b>Invalid monitor id \"" + e.parameter.monitor + "\"</b> pass as ?monitor=MONITOR");

  // Generating the URL
  var publishedURL = "https://docs.google.com/spreadsheets/u/0/d/" + ss.getId() + "/htmlembed/sheet?range=a3:z&gid=" + sheet.getSheetId();

  // Fetching the site
  var response = UrlFetchApp.fetch(publishedURL, {'muteHttpExceptions': true}).getContentText();

  // Getting the background color from paramter (default is black)
  var bg = e.parameter.bg;
  if (bg == null)
    var bg = "black";

  // Defining the styling (I know this way is lazy)
  var styling = "<style>\
body, div {\
background-color: " + bg + " !important;\
display: flex;\
justify-content: center;\
align-items: center;\
}\
</style>";

  // Returning the webpage from original data combined with styling
  return HtmlService.createHtmlOutput(response+styling);
}

这在页面中进一步居中,并且有一个黑色边框以填充跨页之外的屏幕sheet

但是 URL-approach 有一个非常明显的缺点:它不会每秒更新,只有在页面刷新时才会更新

然后我尝试了什么

通过 html 或 js

每秒刷新一次网页

这应该可以,但是由于页面加载 "so slowly",如果我每秒刷新一次,我将有一半时间看到空白页面

正在从客户端获取 URL

利用 js fetch 函数,我可以在后台获取客户端上的源,这样更新会更快,但是我 运行 进入 cross-origin 资源共享(CORS ) 问题在于 Google 不会让我在请求来自客户端时获取源。 (当我在 GScript 中获取它时,它确实有效。)

通过 WebApp 从客户端获取源代码

我最后的决定是从 WebApp 中获取源代码,实习生从传播中获取它sheet,但显然我不能允许 WebApp 的 CORS。

我不知道的事

如何获得 a) 即时更新和 b) 格式正确的中间地带?

我还能用 URL 做些什么吗?喜欢 /htmlembed

https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/gviz/tq?tqx=out:html&tq&gid=0

如所述in this medium post

可以通过缓存获取函数的响应并仅在页面发生变化时刷新页面来实现这一点,就像@TheMaster 所建议的那样。我还从 this post 添加了一个简单的哈希函数,并使用正则表达式来保护代码免受 HTML 注入。

以下代码将在最后一次更新完成后立即刷新页面(大约每秒)。这仍然比在编辑器中慢,因此您可能希望在原始问题中使用解决方案 1。

monitor.gs

/**
 * Only needs acced to the spredsheet the code is installed in
 * @OnlyCurrentDoc
 */

function doGet(e) {
  return HtmlService.createHtmlOutputFromFile("frame");
}


// Fetching the live content from URL
function fetchContent(publishedURL, e) {
  // Fetching the site
  var response = UrlFetchApp.fetch(publishedURL, {'muteHttpExceptions': true}).getContentText();

  // Getting the background color from paramter (default is black)
  var bg = e.parameter.bg;
  if (bg == null)
    var bg = "black";

  // Creating and returning the response
  var template = HtmlService.createTemplateFromFile("style");
  template.bg = /\w+/.exec(bg)[0]; // Setting the background-color
  return template.evaluate().append(response);
}

// Returns the live content if it has cahnged, null otherways
function getContent(e, currentHash) {
  // Getting spreadsheet app
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  // Getting sheet
  var sheet = ss.getSheetByName("Monitor " + e.parameter.monitor);
  //Return error if specified sheet does not exist
  if (sheet == null)
    return {content: "<b>Invalid monitor id \"" + /\w+/.exec(e.parameter.monitor)[0] + "\"</b> pass as ?monitor=MONITOR"};

  // Generating the URL
  var publishedURL = "https://docs.google.com/spreadsheets/u/0/d/" + ss.getId() + "/htmlembed/sheet?range=a3:z&gid=" + sheet.getSheetId();

  // Returning the content if it is different, null otherways
  var content = fetchContent(publishedURL, e).getContent();
  var hash = strhash(content);
  if (hash == currentHash)
    return null;
  Logger.log(hash);
  return {content: content, hash: hash};
}

(同时追加 this code

frame.html

<!DOCTYPE html>
<html>
  <head>
  <style>
  html {
  display: flex;
  justify-content: center;
  align-items: center;
  }
  </style>
  <script>
  let currentContent = undefined;
  function updateContent(content) {
  let doc = new DOMParser().parseFromString(content, "text/html")
  let sheets_viewport = doc.getElementById("sheets-viewport");

  console.log("Current hash: " + currentContent);
  if (content !== null) {
  document.open();
  document.write(content.content);
  document.close();

  console.log("refreshed.");
  currentContent = content.hash;
  console.log("New hash: " + currentContent);
  } else
  console.log("Nothing to refresh.");

  refresh();
  }
  function go(location) {
  google.script.run.withSuccessHandler(updateContent).getContent(location, currentContent);
  }
  refresh();
  function refresh() {console.log("refreshing..."); google.script.url.getLocation(go);}
  </script>
  </head>
  <body>
<div>
<p>Loading...</p>
</div>
  </body>
</html>

style.html

<style>
body, div {
background-color: <?= bg ?> !important;
display: flex;
justify-content: center;
align-items: center;
}
</style>