前端PWA:让你的网站变成App
前端PWA让你的网站变成App毒舌时刻前端PWA这不是噱头吗PWA有什么用用户直接用浏览器不就好了——结果用户体验差无法离线访问我有原生App不需要PWA——结果开发成本高维护困难PWA就是加个manifest和service worker多简单——结果功能不完整用户体验差。醒醒吧PWA不是简单的技术组合而是一种现代化的Web应用模式为什么你需要这个离线访问即使没有网络也能访问应用安装到主屏幕像原生App一样方便使用推送通知及时向用户发送重要信息性能提升缓存静态资源加快加载速度跨平台一次开发多平台运行反面教材!-- 反面教材不完整的PWA配置 -- !DOCTYPE html html head title我的PWA应用/title !-- 缺少manifest.json -- !-- 缺少service worker -- /head body h1我的PWA应用/h1 p这是一个PWA应用/p /body /html// 反面教材简单的service worker // service-worker.js self.addEventListener(install, event { console.log(Service Worker 安装); }); self.addEventListener(activate, event { console.log(Service Worker 激活); }); self.addEventListener(fetch, event { console.log(Service Worker 拦截请求); });正确的做法!-- 正确的做法完整的PWA配置 -- !DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title我的PWA应用/title !-- 添加manifest.json -- link relmanifest href/manifest.json !-- 添加主题颜色 -- meta nametheme-color content#317EFB !-- 添加Apple Touch Icon -- link relapple-touch-icon href/icons/icon-192x192.png !-- 添加预加载 -- link relpreload href/style.css asstyle link relpreload href/script.js asscript link relstylesheet href/style.css /head body h1我的PWA应用/h1 p这是一个完整的PWA应用/p button idnotification-btn发送通知/button script src/script.js/script script // 注册service worker if (serviceWorker in navigator) { window.addEventListener(load, () { navigator.serviceWorker.register(/service-worker.js) .then(registration { console.log(Service Worker 注册成功:, registration.scope); }) .catch(error { console.log(Service Worker 注册失败:, error); }); }); } /script /body /html// 正确的做法manifest.json { name: 我的PWA应用, short_name: PWA应用, description: 一个完整的PWA应用示例, start_url: /, display: standalone, background_color: #ffffff, theme_color: #317EFB, icons: [ { src: /icons/icon-72x72.png, sizes: 72x72, type: image/png, purpose: any }, { src: /icons/icon-96x96.png, sizes: 96x96, type: image/png, purpose: any }, { src: /icons/icon-128x128.png, sizes: 128x128, type: image/png, purpose: any }, { src: /icons/icon-144x144.png, sizes: 144x144, type: image/png, purpose: any }, { src: /icons/icon-152x152.png, sizes: 152x152, type: image/png, purpose: any }, { src: /icons/icon-192x192.png, sizes: 192x192, type: image/png, purpose: any }, { src: /icons/icon-384x384.png, sizes: 384x384, type: image/png, purpose: any }, { src: /icons/icon-512x512.png, sizes: 512x512, type: image/png, purpose: any } ] }// 正确的做法完整的service worker // service-worker.js const CACHE_NAME pwa-app-cache-v1; const ASSETS_TO_CACHE [ /, /index.html, /style.css, /script.js, /manifest.json, /icons/icon-72x72.png, /icons/icon-96x96.png, /icons/icon-128x128.png, /icons/icon-144x144.png, /icons/icon-152x152.png, /icons/icon-192x192.png, /icons/icon-384x384.png, /icons/icon-512x512.png ]; // 安装Service Worker self.addEventListener(install, event { event.waitUntil( caches.open(CACHE_NAME) .then(cache { console.log(Cache opened); return cache.addAll(ASSETS_TO_CACHE); }) .then(() self.skipWaiting()) ); }); // 激活Service Worker self.addEventListener(activate, event { const cacheWhitelist [CACHE_NAME]; event.waitUntil( caches.keys().then(cacheNames { return Promise.all( cacheNames.map(cacheName { if (cacheWhitelist.indexOf(cacheName) -1) { return caches.delete(cacheName); } }) ); }) .then(() self.clients.claim()) ); }); // 拦截网络请求 self.addEventListener(fetch, event { event.respondWith( caches.match(event.request) .then(response { // 如果缓存中有响应直接返回 if (response) { return response; } // 否则发起网络请求 return fetch(event.request) .then(response { // 如果响应有效缓存一份 if (response response.status 200 response.type basic) { const responseToCache response.clone(); caches.open(CACHE_NAME) .then(cache { cache.put(event.request, responseToCache); }); } return response; }) .catch(error { // 网络错误时返回离线页面 if (event.request.mode navigate) { return caches.match(/offline.html); } }); }) ); }); // 处理推送通知 self.addEventListener(push, event { const data event.data.json(); const options { body: data.body, icon: /icons/icon-192x192.png, badge: /icons/icon-72x72.png, data: { url: data.url } }; event.waitUntil( self.registration.showNotification(data.title, options) ); }); // 处理通知点击 self.addEventListener(notificationclick, event { event.notification.close(); event.waitUntil( clients.openWindow(event.notification.data.url) ); });// 正确的做法使用推送通知 // script.js // 请求通知权限 function requestNotificationPermission() { if (Notification in window) { Notification.requestPermission().then(permission { if (permission granted) { console.log(通知权限已授予); } else { console.log(通知权限被拒绝); } }); } } // 发送通知 function sendNotification() { if (serviceWorker in navigator PushManager in window) { navigator.serviceWorker.ready.then(registration { registration.showNotification(测试通知, { body: 这是一条测试通知, icon: /icons/icon-192x192.png, badge: /icons/icon-72x72.png, data: { url: / } }); }); } } // 页面加载时请求通知权限 window.addEventListener(load, () { requestNotificationPermission(); // 绑定按钮点击事件 const notificationBtn document.getElementById(notification-btn); if (notificationBtn) { notificationBtn.addEventListener(click, sendNotification); } }); // 检查是否是PWA模式 function checkPwaMode() { const isPwa window.matchMedia((display-mode: standalone)).matches || window.navigator.standalone || document.referrer.includes(android-app://); if (isPwa) { console.log(应用以PWA模式运行); } else { console.log(应用以浏览器模式运行); } } checkPwaMode();毒舌点评看看这才叫前端PWA不是简单地添加manifest和service worker而是构建一个完整的PWA应用包括离线访问、推送通知、安装到主屏幕等功能。记住PWA不是替代原生App而是一种补充。它可以让你的Web应用获得类似原生App的体验同时保持Web的跨平台优势。所以别再觉得PWA是噱头了它是现代Web开发的重要方向总结manifest.json配置应用名称、图标、显示模式等Service Worker实现离线缓存、推送通知等功能离线访问缓存静态资源确保无网络时也能访问安装到主屏幕提供类似原生App的入口推送通知及时向用户发送重要信息性能优化缓存策略、预加载等可访问性确保PWA对所有用户都友好跨平台一次开发多平台运行PWA让你的网站变成真正的应用