如何将真正实时的 Google 表格电子表格嵌入到网页中?
How do I embed a truly live Google Sheets spreadsheet into a webpage?
我想要的
一个显示真正实时 sheet 的网站(当 sheet 从其他地方更改时立即更新,例如在编辑器中),但居中于屏幕且没有菜单等(例如在 2b)
具体是哪个网站
- 显示 sheet 的 Google 张展开sheet,格式正确
- 在没有任何用户输入的情况下大约每秒更新一次 sheet 直播
- 不包含 Google 工作表编辑 headers
- 将页面中的内容居中,并在跨页外用黑色边框填充屏幕sheet
我所知道的
经过多次 Google 搜索,我找到了两个符合我目标的结果:
1。 Google 没有菜单的工作表编辑器
您可以直接在编辑器中显示 sheet,只需将 ?rm=minimal
添加到 url,如
https://docs.google.com/spreadsheets/d/SPREADSHEET_ID/view?rm=minimal#gid=SHEET_ID
这个
- 实时更新数据,只要 sheet 发生变化
但是
- 显示行和列 headers(A、B、C、...、1、2、3、...)
- 显示 sheet 选择和 "insert x rows below"
- 未居中且没有黑色背景
2。其他 URL 东西
当您编辑 URL 并将 /edit...
替换为 /htmlembed/sheet?gid=SHEET_ID
时,如
https://docs.google.com/spreadsheets/u/0/d/SPREADSHEET_ID/htmlembed/sheet?gid=SHEET_ID
这个
- 不包含任何headers或类似的
- 甚至允许我使用
range=A1NOTATION
参数 仅指定要显示的固定 运行ge
可以使用 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
可以通过缓存获取函数的响应并仅在页面发生变化时刷新页面来实现这一点,就像@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>
我想要的
一个显示真正实时 sheet 的网站(当 sheet 从其他地方更改时立即更新,例如在编辑器中),但居中于屏幕且没有菜单等(例如在 2b)
具体是哪个网站
- 显示 sheet 的 Google 张展开sheet,格式正确
- 在没有任何用户输入的情况下大约每秒更新一次 sheet 直播
- 不包含 Google 工作表编辑 headers
- 将页面中的内容居中,并在跨页外用黑色边框填充屏幕sheet
我所知道的
经过多次 Google 搜索,我找到了两个符合我目标的结果:
1。 Google 没有菜单的工作表编辑器
您可以直接在编辑器中显示 sheet,只需将 ?rm=minimal
添加到 url,如
https://docs.google.com/spreadsheets/d/SPREADSHEET_ID/view?rm=minimal#gid=SHEET_ID
这个
- 实时更新数据,只要 sheet 发生变化
但是
- 显示行和列 headers(A、B、C、...、1、2、3、...)
- 显示 sheet 选择和 "insert x rows below"
- 未居中且没有黑色背景
2。其他 URL 东西
当您编辑 URL 并将 /edit...
替换为 /htmlembed/sheet?gid=SHEET_ID
时,如
https://docs.google.com/spreadsheets/u/0/d/SPREADSHEET_ID/htmlembed/sheet?gid=SHEET_ID
这个
- 不包含任何headers或类似的
- 甚至允许我使用
range=A1NOTATION
参数 仅指定要显示的固定 运行ge
可以使用 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
可以通过缓存获取函数的响应并仅在页面发生变化时刷新页面来实现这一点,就像@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>