新增pwa支持

This commit is contained in:
kura 2025-01-16 14:58:50 +08:00
parent 26eff2fcb3
commit e4702b877f
9 changed files with 2544 additions and 19 deletions

View File

@ -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"
} }
} }

View File

@ -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);

View File

@ -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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
static/icon64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -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',
}, },

2412
yarn.lock

File diff suppressed because it is too large Load Diff