背景
INFO
上篇总结了如何实现网站更新的功能,现在还有另外的一种做法pwa技术实现;
创建项目
用vite+ts+vue
创建一个空项目
bash
pnpm create vite vite-pwa-demo --template vue-ts
安装插件
安装完成之后,需要再次安装pwa
插件
bash
pnpm add -D vite-plugin-pwa
配置插件
完成安装之后,需要改一下vite.config.ts
文件,添加pwa
插件
ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { VitePWA } from "vite-plugin-pwa";
export default defineConfig({
plugins: [
vue(),
VitePWA({
// prompt 弹框模式。 autoupdate 自动更新模式
registerType: "prompt",
devOptions: {
enabled: true,
},
workbox: {
cleanupOutdatedCaches: true,
},
manifest: {},
}),
],
server: {
port: 5177,
},
});
接着需要在vite-env.d.ts
中添加对应的服务:
ts
declare module "virtual:pwa-register/vue" {
import type { Ref } from "vue";
import type { RegisterSWOptions } from "vite-plugin-pwa/types";
export type { RegisterSWOptions };
export function useRegisterSW(options?: RegisterSWOptions): {
needRefresh: Ref<boolean>;
offlineReady: Ref<boolean>;
updateServiceWorker: (reloadPage?: boolean) => Promise<void>;
};
}
接着在tsconfig.json
中配置
json
{
"compilerOptions": {
// 添加这一行
"types": ["vite-plugin-pwa/client", "vite-plugin-pwa/vue", "vite/client"]
}
}
更新检测
ts
// 核心代码
import { useRegisterSW } from "virtual:pwa-register/vue";
const { offlineReady, needRefresh, updateServiceWorker } = useRegisterSW({
// 每隔3s检查一次是否有新版本
onRegistered(r) {
if (r) {
setInterval(() => {
r.update();
}, 1000 * 3);
}
},
});
编写更新弹框
vue
<script setup lang="ts">
import { useRegisterSW } from "virtual:pwa-register/vue";
import { ref, watch } from "vue";
import { ElMessage } from "element-plus";
const { offlineReady, needRefresh, updateServiceWorker } = useRegisterSW({
onRegistered(r) {
if (r && !check.value) {
setInterval(() => {
r.update();
}, 1000 * 3);
}
},
});
// 如果是强制更新,只需要needRefresh.value 即可;
// 用另外的变量控制弹框的显示
const check = ref(needRefresh.value);
const loading = ref(false);
const btnText = ref("立即更新");
// 更新
const updataPage = async () => {
loading.value = true;
btnText.value = "正在更新中...";
await updateServiceWorker();
};
// 关闭弹框
const close = () => {
check.value = false;
loading.value = false;
btnText.value = "立即更新";
};
// 更新的时候禁止关闭
const beforeClose = (done: any) => {
if (!loading.value) {
return done();
}
ElMessage({
message: "正在进行更新, 请稍等...",
type: "warning",
});
};
// 没3s会更新needRefresh.value的状态,所以这里监听一下即可;
watch(
() => needRefresh.value,
val => {
check.value = val;
}
);
</script>
<template>
<div>======11111213+++---</div>
<el-dialog
v-model="check"
append-to-body
class="w-update"
draggable
width="410px"
:before-close="beforeClose"
>
<template #header></template>
<div class="w-update-icon"></div>
<h3>新版本来袭:</h3>
<p>更新时间:最近更新</p>
<p>更新内容:更新的内容呢还请详看上线邮件~</p>
<p style="color: #ff0000; font-size: 12px">
如果您暂时不想更新(如:您正在操作内容),点击关闭按钮可关闭,后续想更新只需要刷新页面进行更新即可~如果想使用新功能,请点击更新按钮即可
</p>
<template #footer>
<el-button type="primary" @click="updataPage" :loading="loading">
{{ btnText }}
</el-button>
<el-button type="default" :loading="loading" @click="close">
暂时不更新
</el-button>
</template>
</el-dialog>
</template>
<style scoped>
.w-update {
position: relative;
}
.w-update-icon {
position: absolute;
top: -50px;
left: 50%;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
background: linear-gradient(
50deg,
var(--el-color-primary),
var(--el-color-primary-light-7)
);
border-radius: 50%;
transform: translateX(-50%);
}
.w-update-icon i {
font-size: 50px;
color: var(--el-color-white);
}
.w-update-cup {
position: absolute;
right: 20px;
bottom: 70px;
font-size: 80px;
-webkit-text-fill-color: transparent;
background-image: linear-gradient(
var(--el-color-primary-light-7),
var(--el-color-primary-light-9)
);
background-clip: text;
}
</style>
<style>
.w-update.el-dialog {
margin-top: 30vh !important;
border-radius: 15px;
}
.w-update .el-dialog__body {
margin: 0 40px 0 40px;
}
.w-update .el-dialog__footer {
text-align: center !important;
}
.w-update .el-button {
margin-bottom: 20px;
border-radius: 20px;
}
</style>
测试
测试的话,可以上传服务器或者本地nginx
测试;
项目执行pnpm run build
将生成dist
文件夹,将dist
文件夹上传到服务器或者nginx的html文件夹中
即可;
然后等待页面弹框即可;