思路:无论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();