GAS单页应用使用google.script.history导航刷新后点击后退返回空白屏
问题描述
使用google.script.history.push和google.script.history.setChangeHandler开发Google Apps Script单页应用时,仅在页面刷新后点击浏览器前进/后退按钮会返回空白屏,未刷新时所有功能均正常。该问题可在谷歌Chrome(桌面端、移动端)、微软Edge浏览器复现,三星移动端浏览器运行正常。对桌面端用户影响较小,因为用户使用应用时很少主动刷新,但移动端用户上下滑动页面到顶/底部时容易误触刷新,会意外遇到空白屏问题。
复现步骤
- 在浏览器中打开GAS应用,此时可见一个蓝色方块和2个按钮
- 点击「Show Red ONLY」按钮,页面显示红色方块
- 点击「Show Blue ONLY」按钮,页面显示蓝色方块
- 点击浏览器「后退」按钮,页面正常显示红色方块,运行正常
- 点击浏览器「前进」按钮,页面正常显示蓝色方块,无异常
- 点击浏览器「刷新」按钮,页面依据URL的"Color"参数仍正常显示蓝色方块,无异常
- 此时bug触发:点击浏览器「后退」按钮,预期显示红色方块,但实际返回空白屏
只要用户未刷新页面,使用浏览器前进/后退按钮在应用内导航均正常,问题是否复现取决于使用的浏览器类型。
原始代码
服务端脚本代码
function doGet(e){ let htmltemplate = HtmlService.createTemplateFromFile("Home.html"); let htmloutput = htmltemplate.evaluate(); return htmloutput; }
前端HTML代码(Home.html)
<!DOCTYPE html> <html> <head> <base target="_top"> </head> <body> <button onclick="showRed();">Show Red ONLY</button> <button onclick="showBlue();">Show Blue ONLY</button> <div id="Red" style="width:200px; height: 200px; background-color:red;">Red Square</div> <div id="Blue" style="width:200px; height: 200px; background-color:blue;">Blue Square</div> <script> function showRed(){ let now = new Date(); let state = {"timestamp": now.getTime()}; let params = {"Color": "Red"}; google.script.history.push(state, params); renderPage(); } function showBlue(){ let now = new Date(); let state = {"timestamp": now.getTime()}; let params = {"Color": "Blue"}; google.script.history.push(state, params); renderPage(); } function renderPage(){ google.script.url.getLocation(function(location) { strColor = location.parameter.Color; if(strColor === "Red"){ document.getElementById("Red").style.display = "block"; document.getElementById("Blue").style.display = "none"; }else{ document.getElementById("Red").style.display = "none"; document.getElementById("Blue").style.display = "block"; } }); } google.script.history.setChangeHandler(function (e) { renderPage() }); document.addEventListener('DOMContentLoaded', renderPage()); </script> </body> </html>
问题根因
- DOMContentLoaded事件绑定错误:代码中写的是
renderPage(),会在绑定事件时立即执行函数,而不是DOM加载完成后触发,导致初始状态渲染时序异常 - 异步API读取异常:
google.script.url.getLocation是异步接口,页面刷新后调用历史栈导航时,该接口无法正确读取历史条目中的参数,导致strColor取值为undefined,两个方块都被设置为隐藏,出现空白屏 - 代码逻辑冗余:
setChangeHandler的回调参数本身就包含了历史条目的参数和状态,不需要额外调用google.script.url.getLocation获取参数,增加了异步调用的时序风险
修复方案
修改Home.html中的script部分代码即可解决问题,核心改动为:修正DOM事件绑定逻辑、优先从历史事件对象取参数、增加默认显示逻辑避免空白。
修复后完整script代码如下:
function showRed(){ let now = new Date(); let state = {"timestamp": now.getTime()}; let params = {"Color": "Red"}; google.script.history.push(state, params); renderPage("Red"); } function showBlue(){ let now = new Date(); let state = {"timestamp": now.getTime()}; let params = {"Color": "Blue"}; google.script.history.push(state, params); renderPage("Blue"); } // 改造renderPage支持直接传入参数,避免异步读取异常 function renderPage(strColor = null){ if(strColor){ updateDisplay(strColor) }else{ google.script.url.getLocation(function(location) { updateDisplay(location.parameter.Color); }); } } // 抽离显示更新逻辑,增加默认值避免空白 function updateDisplay(strColor){ if(strColor === "Red"){ document.getElementById("Red").style.display = "block"; document.getElementById("Blue").style.display = "none"; }else{ document.getElementById("Red").style.display = "none"; document.getElementById("Blue").style.display = "block"; } } // 从历史事件对象直接取参数,不需要再异步读url google.script.history.setChangeHandler(function (e) { renderPage(e.parameter.Color) }); // 修正事件绑定,传函数引用而不是执行结果 document.addEventListener('DOMContentLoaded', renderPage);
内容的提问来源于stack exchange,提问作者Gaston Doiron
相关产品推荐
相关产品推荐

