Vue
Vue 3
对于 Vue 3
你可以使用Vite
内置的虚拟模块 virtual:pwa-register/vue
它能返回 composition api
参照 (ref<boolean>
) offlineReady
和 needRefresh
.
类型声明
提示
如果你的 TypeScript 构建时或 IDE 抱怨在导入时找不到模块或类型定义,请将以下内容添加到tsconfig.json
的 compilerOptions.types
数组中:
{
"compilerOptions": {
"types": ["vite-plugin-pwa/client"]
}
}
或者你可以添加以下引用到任何 d.ts
文件中(例如,在 vite-env.d.ts
或 global.d.ts
中):
/// <reference types="vite-plugin-pwa/client" />
从0.14.5
版本开始,你还可以为 vue 使用类型定义,而不是vite-plugin-pwa/client
:
{
"compilerOptions": {
"types": ["vite-plugin-pwa/vue"]
}
}
或者你可以添加以下引用在任何的 d.ts
文件中(例如,在 vite-env.d.ts
或 global.d.ts
中):
/// <reference types="vite-plugin-pwa/vue" />
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>;
};
}
更新提示
你可以使用 ReloadPrompt.vue
组件:
ReloadPrompt.vue
<script setup lang="ts">
import { useRegisterSW } from 'virtual:pwa-register/vue';
const { offlineReady, needRefresh, updateServiceWorker } = useRegisterSW();
async function close() {
offlineReady.value = false;
needRefresh.value = false;
}
</script>
<template>
<div v-if="offlineReady || needRefresh" class="pwa-toast" role="alert">
<div class="message">
<span v-if="offlineReady"> App ready to work offline </span>
<span v-else>
New content available, click on reload button to update.
</span>
</div>
<button v-if="needRefresh" @click="updateServiceWorker()">Reload</button>
<button @click="close">Close</button>
</div>
</template>
<style>
.pwa-toast {
position: fixed;
right: 0;
bottom: 0;
margin: 16px;
padding: 12px;
border: 1px solid #8885;
border-radius: 4px;
z-index: 1;
text-align: left;
box-shadow: 3px 4px 5px 0 #8885;
background-color: white;
}
.pwa-toast .message {
margin-bottom: 8px;
}
.pwa-toast button {
border: 1px solid #8885;
outline: none;
margin-right: 5px;
border-radius: 2px;
padding: 3px 10px;
}
</style>
定期 SW 更新
正如定期更新 Service Worker解释,你可以在你的应用中使用虚拟模块virtual:pwa-register/vue
来配置此行为:
import { useRegisterSW } from 'virtual:pwa-register/vue';
const intervalMS = 60 * 60 * 1000;
const updateServiceWorker = useRegisterSW({
onRegistered(r) {
r &&
setInterval(() => {
r.update();
}, intervalMS);
},
});
间隔必须以毫秒为单位,在上面的例子中,它被配置为每小时检查一次service worker。
警告
这只适用于在导入任何虚拟模块或使用 workbox-window
模块时
因为 workbox-window
使用基于时间的 heuristic
算法来处理 service worker 更新,因此,如果您构建了自己的 service worker 并再次注册它,如果上次注册和本次注册之间的时间不足 1 分钟,那么workbox-window
将把 service worker update found
事件作为外部事件处理,因此可能会有很奇怪的行为(例如,如果使用 prompt
,将显示离线准备就绪的对话框,而不是显示新内容可用的对话框;如果使用 autoUpdate
,将显示离线准备就绪的对话框,然而它不应该显示)。
Vue 2
因为这个插件只支持Vue 3
,所以你不能使用虚拟模块 virtual:pwa-register/vue
。
你可以把useRegisterSW.js
mixin
拷贝到你的@/mixins/
目录下,让它工作:
useRegisterSW.js
export default {
name: 'useRegisterSW',
data() {
return {
updateSW: undefined,
offlineReady: false,
needRefresh: false,
};
},
async mounted() {
try {
const { registerSW } = await import('virtual:pwa-register');
const vm = this;
this.updateSW = registerSW({
immediate: true,
onOfflineReady() {
vm.offlineReady = true;
vm.onOfflineReadyFn();
},
onNeedRefresh() {
vm.needRefresh = true;
vm.onNeedRefreshFn();
},
onRegistered(swRegistration) {
swRegistration && vm.handleSWManualUpdates(swRegistration);
},
onRegisterError(e) {
vm.handleSWRegisterError(e);
},
});
} catch {
console.log('PWA disabled.');
}
},
methods: {
async closePromptUpdateSW() {
this.offlineReady = false;
this.needRefresh = false;
},
onOfflineReadyFn() {
console.log('onOfflineReady');
},
onNeedRefreshFn() {
console.log('onNeedRefresh');
},
updateServiceWorker() {
this.updateSW && this.updateSW(true);
},
handleSWManualUpdates(swRegistration) {},
handleSWRegisterError(error) {},
},
};
更新提示
你可以使用 ReloadPrompt.vue
组件:
ReloadPrompt.vue
<script>
import useRegisterSW from '@/mixins/useRegisterSW';
export default {
name: 'ReloadPrompt',
mixins: [useRegisterSW],
};
</script>
<template>
<div v-if="offlineReady || needRefresh" class="pwa-toast" role="alert">
<div class="message">
<span v-if="offlineReady"> App ready to work offline </span>
<span v-else>
New content available, click on reload button to update.
</span>
</div>
<button v-if="needRefresh" @click="updateServiceWorker()">Reload</button>
<button @click="close">Close</button>
</div>
</template>
<style>
.pwa-toast {
position: fixed;
right: 0;
bottom: 0;
margin: 16px;
padding: 12px;
border: 1px solid #8885;
border-radius: 4px;
z-index: 1;
text-align: left;
box-shadow: 3px 4px 5px 0 #8885;
}
.pwa-toast .message {
margin-bottom: 8px;
}
.pwa-toast button {
border: 1px solid #8885;
outline: none;
margin-right: 5px;
border-radius: 2px;
padding: 3px 10px;
}
</style>
定期 SW 更新
正如 定期更新 Service Worker中解释,你可以在你的应用中使用useRegisterSW.js
mixin
用这段代码来配置此行为:
<script>
import useRegisterSW from '@/mixins/useRegisterSW';
const intervalMS = 60 * 60 * 1000;
export default {
name: 'ReloadPrompt',
mixins: [useRegisterSW],
methods: {
handleSWManualUpdates(r) {
r &&
setInterval(() => {
r.update();
}, intervalMS);
},
},
};
</script>
间隔必须以毫秒为单位,在上面的例子中,它被配置为每小时检查一次 service worker。
警告
这只适用于在导入任何虚拟模块或使用 workbox-window
模块时
因为 workbox-window
使用基于时间的 heuristic
算法来处理 service worker 更新,因此,如果您构建了自己的 service worker 并再次注册它,如果上次注册和本次注册之间的时间不足 1 分钟,那么workbox-window
将把 service worker update found
事件作为外部事件处理,因此可能会有很奇怪的行为(例如,如果使用 prompt
,将显示离线准备就绪的对话框,而不是显示新内容可用的对话框;如果使用 autoUpdate
,将显示离线准备就绪的对话框,然而它不应该显示)。