新增pwa支持
This commit is contained in:
parent
26eff2fcb3
commit
e4702b877f
@ -22,7 +22,8 @@
|
|||||||
"three": "^0.172.0",
|
"three": "^0.172.0",
|
||||||
"vue": "^3.3.0",
|
"vue": "^3.3.0",
|
||||||
"vue-i18n": "^9.1.9",
|
"vue-i18n": "^9.1.9",
|
||||||
"vue-router": "^4.5.0"
|
"vue-router": "^4.5.0",
|
||||||
|
"register-service-worker": "^1.7.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rushstack/eslint-patch": "^1.6.1",
|
"@rushstack/eslint-patch": "^1.6.1",
|
||||||
@ -44,6 +45,8 @@
|
|||||||
"sass-loader": "^13.3.3",
|
"sass-loader": "^13.3.3",
|
||||||
"typescript": "^4.9.4",
|
"typescript": "^4.9.4",
|
||||||
"vite": "4.1.4",
|
"vite": "4.1.4",
|
||||||
"vue-tsc": "^1.0.24"
|
"vite-plugin-pwa": "^0.17.5",
|
||||||
|
"vue-tsc": "^1.0.24",
|
||||||
|
"workbox-window": "^7.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
src/main.ts
19
src/main.ts
@ -3,6 +3,25 @@ import App from './App.vue'
|
|||||||
import 'ant-design-vue/dist/reset.css';
|
import 'ant-design-vue/dist/reset.css';
|
||||||
import Antd from 'ant-design-vue';
|
import Antd from 'ant-design-vue';
|
||||||
import router from './router/router';
|
import router from './router/router';
|
||||||
|
import { registerSW } from 'virtual:pwa-register'
|
||||||
|
import { isPwa, showPwaInstallPrompt } from './utils/pwa';
|
||||||
|
|
||||||
|
const updateSW = registerSW({
|
||||||
|
onNeedRefresh() {
|
||||||
|
// 当发现新版本时,可以在这里提示用户
|
||||||
|
console.log('发现新版本')
|
||||||
|
},
|
||||||
|
onOfflineReady() {
|
||||||
|
// 当离线功能准备就绪时
|
||||||
|
console.log('应用已经可以离线使用')
|
||||||
|
if (isPwa()) {
|
||||||
|
console.log('PWA 模式')
|
||||||
|
} else {
|
||||||
|
// showPwaInstallPrompt()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
app.use(Antd);
|
app.use(Antd);
|
||||||
app.use(router);
|
app.use(router);
|
||||||
|
@ -2,13 +2,43 @@ import { createRouter, createWebHashHistory } from "vue-router";
|
|||||||
import Index from "../pages/file/index.vue";
|
import Index from "../pages/file/index.vue";
|
||||||
import Voice from "../pages/voice/webrtcVoice.vue";
|
import Voice from "../pages/voice/webrtcVoice.vue";
|
||||||
import PointShader from "../pages/pointShader/pointShader.vue";
|
import PointShader from "../pages/pointShader/pointShader.vue";
|
||||||
|
import { disablePwaPrompt, enablePwaPrompt } from '../utils/pwa';
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(),
|
history: createWebHashHistory(),
|
||||||
routes: [
|
routes: [
|
||||||
{ path: "/", component: Index },
|
{
|
||||||
{ path: "/voice", component: Voice },
|
path: "/",
|
||||||
{ path: "/pointShader", component: PointShader },
|
component: Index,
|
||||||
|
meta: {
|
||||||
|
showPwaPrompt: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/voice",
|
||||||
|
component: Voice,
|
||||||
|
meta: {
|
||||||
|
showPwaPrompt: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/pointShader",
|
||||||
|
component: PointShader,
|
||||||
|
meta: {
|
||||||
|
showPwaPrompt: false
|
||||||
|
}
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 路由守卫控制 PWA 提示
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
if (to.meta.showPwaPrompt) {
|
||||||
|
enablePwaPrompt();
|
||||||
|
} else {
|
||||||
|
disablePwaPrompt();
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
11
src/types/virtual-pwa-register.d.ts
vendored
Normal file
11
src/types/virtual-pwa-register.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
declare module 'virtual:pwa-register' {
|
||||||
|
export interface RegisterSWOptions {
|
||||||
|
immediate?: boolean
|
||||||
|
onNeedRefresh?: () => void
|
||||||
|
onOfflineReady?: () => void
|
||||||
|
onRegistered?: (registration: ServiceWorkerRegistration | undefined) => void
|
||||||
|
onRegisterError?: (error: any) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerSW(options?: RegisterSWOptions): (reloadPage?: boolean) => Promise<void>
|
||||||
|
}
|
46
src/utils/pwa.ts
Normal file
46
src/utils/pwa.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// PWA 安装状态
|
||||||
|
let deferredPrompt: any = null;
|
||||||
|
|
||||||
|
// 控制是否显示安装提示
|
||||||
|
let showInstallPrompt = true;
|
||||||
|
|
||||||
|
// 监听 beforeinstallprompt 事件
|
||||||
|
window.addEventListener('beforeinstallprompt', (e) => {
|
||||||
|
if (!showInstallPrompt) {
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deferredPrompt = e;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 检查是否为 PWA 模式
|
||||||
|
export const isPwa = () => {
|
||||||
|
return window.matchMedia('(display-mode: standalone)').matches ||
|
||||||
|
(window.navigator as any).standalone ||
|
||||||
|
document.referrer.includes('android-app://');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 禁用 PWA 安装提示
|
||||||
|
export const disablePwaPrompt = () => {
|
||||||
|
showInstallPrompt = false;
|
||||||
|
if (deferredPrompt) {
|
||||||
|
deferredPrompt = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 启用 PWA 安装提示
|
||||||
|
export const enablePwaPrompt = () => {
|
||||||
|
showInstallPrompt = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 手动触发 PWA 安装提示
|
||||||
|
export const showPwaInstallPrompt = async () => {
|
||||||
|
if (!deferredPrompt) {
|
||||||
|
console.log('No PWA installation prompt available');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deferredPrompt.prompt();
|
||||||
|
const { outcome } = await deferredPrompt.userChoice;
|
||||||
|
deferredPrompt = null;
|
||||||
|
return outcome;
|
||||||
|
};
|
BIN
static/icon256.png
Normal file
BIN
static/icon256.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
static/icon64.png
Normal file
BIN
static/icon64.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
@ -1,13 +1,43 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import basicSsl from '@vitejs/plugin-basic-ssl'
|
import basicSsl from '@vitejs/plugin-basic-ssl'
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import { VitePWA } from 'vite-plugin-pwa'
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
build: {
|
build: {
|
||||||
// 开发阶段启用源码映射:https://uniapp.dcloud.net.cn/tutorial/migration-to-vue3.html#需主动开启-sourcemap
|
// 开发阶段启用源码映射:https://uniapp.dcloud.net.cn/tutorial/migration-to-vue3.html#需主动开启-sourcemap
|
||||||
sourcemap: process.env.NODE_ENV === 'development',
|
sourcemap: process.env.NODE_ENV === 'development',
|
||||||
},
|
},
|
||||||
plugins: [vue(), basicSsl()],
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
basicSsl(),
|
||||||
|
VitePWA({
|
||||||
|
registerType: 'autoUpdate',
|
||||||
|
manifest: {
|
||||||
|
name: 'P2P Explorer',
|
||||||
|
short_name: 'P2P Explorer',
|
||||||
|
description: 'P2P文件传输与浏览工具',
|
||||||
|
theme_color: '#f5f5f5',//米色
|
||||||
|
background_color: '#f5f5f5',
|
||||||
|
icons: [
|
||||||
|
{
|
||||||
|
src: '/static/icon64.png',
|
||||||
|
sizes: '64x64',
|
||||||
|
type: 'image/png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: '/static/icon256.png',
|
||||||
|
sizes: '256x256',
|
||||||
|
type: 'image/png'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
workbox: {
|
||||||
|
globPatterns: ['**/*.{js,css,html,ico,png,svg,webp}'],
|
||||||
|
runtimeCaching: []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
server: {
|
server: {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user