前端重新部署如何通知用户刷新网页?

156 阅读1分钟

上代码

interface Options {
    timer?: number;
}

type key = 'no-update' | 'update';

export class Updater {
    oldScript: string[];
    newScript: string[];
    timer: number = 0;
    dispatch: Record<string, Function[]>;
    constructor(option?: Options) {
        this.oldScript = [];
        this.newScript = [];
        this.dispatch = {};

        this.init(); // 初始化
        this.timing(option?.timer);
    }

    async init() {
        const html = await this.getHtml();
        this.oldScript = this.parseScript(html);
    }

    static restart() {
        const update = new Updater();
        return update;
    }

    async getHtml() {
        const html = await fetch('/').then((res) => res.text());
        return html;
    }

    parseScript(html: string) {
        const reg = new RegExp(/<script(?:\s+[^>]*)?>(.*?)<\/script\s*>/gi);
        return html.match(reg) as string[];
    }
    // 发布订阅
    on(key: key, fn: Function) {
        (this.dispatch[key] || (this.dispatch[key] = [])).push(fn);
        return this;
    }

    compare(oldArr: string[], newArr: string[]) {
        if (oldArr.length === 0 || newArr.length === 0) return;

        const base = oldArr.length;
        const arr = Array.from(new Set(oldArr.concat(newArr)));
        // 长度相同就没触发更新
        if (base === arr.length) {
            this.dispatch['no-update'] &&
                this.dispatch['no-update'].forEach((fn) => fn());
        } else {
            // 反之跟新了
            this.dispatch['update'] &&
                this.dispatch['update'].forEach((fn) => fn());
        }
    }

    timing(time = 0.5 * 60 * 1000) {
        // 
        this.timer = setInterval(async () => {
            const newHtml = await this.getHtml();
            this.newScript = this.parseScript(newHtml);
            this.compare(this.oldScript, this.newScript);
        }, time);
    }

    clearIntervalFunc() {
        clearInterval(this.timer);
        this.oldScript = [];
        this.newScript = [];
    }
    
    // stop 停止轮询 页面隐藏
    stop() {
        clearInterval(this.timer);
    }
    // 页面可见 重启
    start() {
        this.timing();
    }
}

  1. 需要注意的地方

**调用取消之后需要情况定时器,然后重新init初始化 重新timing**

<script setup lang="ts">
import { Updater } from "@/hooks/versionUpdate/updater";
import { onMounted, ref } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';


const count = ref(0)
const update = ref()


const messageBoxFunc = () => {
    count.value += 1
    ElMessageBox.confirm(
        '版本更新,是否刷新',
        'Warning',
        {
            confirmButtonText: '刷新',
            cancelButtonText: '忽略',
            type: 'warning',
        }
    )
        .then(() => {
            ElMessage({
                type: 'success',
                message: '刷新成功',
            })
            clearLocalStorage()
            location.reload();
        })
        .catch(() => {
            update.value.clearIntervalFunc()
            update.value.init()
            update.value.timing()
            count.value = 0
        })
}

const initUpdater = () => {
    console.log(import.meta.env);
    if (import.meta.env.PROD) {
        update.value = new Updater()
        update.value.on('update', () => {
            console.log('update');

            if (count.value === 0) messageBoxFunc()

        })

        update.value.on('no-update', () => {
            console.log('no-update');
        })
    }


}

// localStorage 清空处token以外的缓存
function clearLocalStorage() {
    const preservedKeysRegex = /^(useToken)$/;

    for (let i = localStorage.length - 1; i >= 0; i--) {
        const key = localStorage.key(i) as string;

        if (!preservedKeysRegex.test(key)) {
            localStorage.removeItem(key);
        }
    }
}

// 检测页面是否可见
const initPageIsshowFunc = () => {
    // 判断浏览器是否支持 Page Visibility API
    if (typeof document.hidden !== "undefined" && import.meta.env.PROD) {
        // 添加可见性状态改变的事件监听器
        document.addEventListener("visibilitychange", handleVisibilityChange);
    }
}

// 处理可见性状态改变的函数
const handleVisibilityChange = () => {
    if (document.hidden) {
        // 页面被隐藏,执行相应的操作
        console.log("页面隐藏");
        update.value.stop()
    } else {
        // 页面重新可见,执行相应的操作
        console.log("页面重新可见");
        update.value.start()
    }
}


onMounted(() => {
    initUpdater()
    initPageIsshowFunc()
});
</script>