思路:无论vue还是react打包都会有dist文件夹,内部有index.html。我是想根据index.html中的script src地址是否改变,判断项目是否有新内容。
具体代码如下
首先先拿到生产环境中index.html文本,由于是单页面应用使用fetch('/?_stamp='+Date.now())来拿到html文本。并获取所有的src地址。
const scriptReg = /\<script.*src=["'](?<src>[^"']+)/gm;async function getScriptSrcs() {const html = await fetch('/?_timestamp=' + Date.now()).then((res) =>res.text(),);scriptReg.lastIndex = 0;let result = [];let match;while ((match = scriptReg.exec(html))) {result.push(match.groups.src);}return result;
}
全局定义lastSrcs表示旧的地址数组,然后和新的newScripts对比,如果长度不同或者某一项不同则表示项目有新内容更新。
async function needUpdate() {const newScripts = await getScriptSrcs();if (!lastSrcs) {lastSrcs = newScripts;return false;}let result = false;if (lastSrcs.length !== newScripts.length) {result = true;}for (let i = 0; i < lastSrcs.length; i++) {if (lastSrcs[i] !== newScripts[i]) {result = true;break;}}lastSrcs = newScripts;return result;
}
最终我们使用轮询的方式监听是否变化。
const autoRefresh=()=>{setTimeout(async()=>{const willUpdate = await needUpdate();if (willUpdate) {const result = confirm('页面有更新,请刷新页面');if (result) {location.reload();}}autoRefresh();},5000);
}
最后在main.ts中引入即可。有什么问题私信哦。
后续:我想加一个可以自动关闭的功能,但是使用window.confirm我无法实现,尝试使用alert也无法成功,然后就想到是不是可以重写这个alert,结果发现果然可以。代码如下:直接复制即可使用,需要在入口文件引入。
let lastSrcs;
let timeoutId: any = 0;
let strHtml,time = 5,timer = null,timer1 = null;
const scriptReg = /\<script.*src=["'](?<src>[^"']+)/gm;async function getScriptSrcs() {const html = await fetch('/?_timestamp=' + Date.now()).then((res) =>res.text(),);scriptReg.lastIndex = 0;let result = [];let match;while ((match = scriptReg.exec(html))) {result.push(match.groups.src);}return result;
}
async function needUpdate() {const newScripts = await getScriptSrcs();if (!lastSrcs) {lastSrcs = newScripts;return false;}let result = false;if (lastSrcs.length !== newScripts.length) {result = true;}for (let i = 0; i < lastSrcs.length; i++) {if (lastSrcs[i] !== newScripts[i]) {result = true;break;}}lastSrcs = newScripts;return result;
}function createMask() {var shield = document.createElement('DIV');shield.id = 'shield';shield.style.position = 'absolute';shield.style.left = '0px';shield.style.top = '0px';shield.style.width = '100%';shield.style.height = document.body.scrollHeight + 'px';shield.style.background = 'transparent';shield.style.textAlign = 'center';shield.style.zIndex = '10000';shield.style.filter = 'alpha(opacity=0)';document.body.appendChild(shield);return shield;
}function createAlert(txt) {var alertFram = document.createElement('DIV');alertFram.id = 'alertFram';alertFram.style.position = 'absolute';alertFram.style.left = '50%';alertFram.style.top = '0';alertFram.style.background = '#fff';alertFram.style.transform = 'translateX(-50%)';alertFram.style.width = '450px';alertFram.style.height = '150px';alertFram.style.textAlign = 'center';alertFram.style.lineHeight = '150px';alertFram.style.zIndex = '10001';strHtml ='<ul style="list-style:none;margin:0px;padding:0px;width:100%;border-radius:10px;overflow:hidden;box-shadow:0 0 5px 5px #ccc">\n';strHtml +=' <li style="background:#1677ff;text-align:left;padding-left:20px;font-size:14px;font-weight:bold;height:40px;line-height:40px;color:#fff">系统提示</li>\n';strHtml +='<li id="_content" style="background:#fff;text-align:center;font-size:14px;height:100px;line-height:100px;">' +txt +'</li>\n';strHtml += `<li style="background:#fff;text-align:right;font-weight:bold;height:50px;line-height:25px;padding-bottom:10px ;padding-right:20px;"><input type="button" id="_btn_click" style="outline:none;cursor:pointer;border:0;width:70px;height:40px;border-radius:20px;background:#1677ff;color:#fff" value="确 定"/></li>\n`;strHtml += '</ul>\n';alertFram.innerHTML = strHtml;document.body.appendChild(alertFram);return alertFram;
}function removerDom(alertFram, mask) {document.body.removeChild(alertFram);document.body.removeChild(mask);window.location.reload();
}function controlTime(alertFram, mask) {timer1 = setInterval(() => {time -= 1;document.getElementById('_content').textContent =`页面有更新,${time}秒后将强制刷新页面!`;if (time === 0) {clearTimeout(timer1);removerDom(alertFram, mask);}}, 1000);
}window.alert = function (txt) {const alertFram = createAlert(txt);const mask = createMask();controlTime(alertFram, mask);const dom = document.getElementById('_btn_click');dom.onclick = () => {removerDom(alertFram, mask);};
};const duration = 5000;function autoRefresh() {timer = setTimeout(async () => {const willUpdate = await needUpdate();let content = `页面有更新,${time}秒后将强制刷新页面!`;if (willUpdate) {clearTimeout(timer);alert(content);} else {autoRefresh();}}, duration);
}
const env = process.env.UMI_ENV;env == 'production' && autoRefresh();