一、渐进式 Web 应用(PWA)的定义
渐进式 Web 应用(Progressive Web App,PWA)是一种结合传统 Web 技术与现代移动应用特性的技术方案,旨在通过 HTML、CSS 和 JavaScript 构建具备原生应用体验的 Web 应用。其核心特性包括:
- 可安装性:用户可将 PWA 添加到设备主屏幕,像原生应用一样独立运行;
- 渐进增强:根据设备和网络环境逐步提升功能,确保基础功能在所有浏览器中可用;
- 技术融合:依赖 Service Workers、Web App Manifest 等现代 Web API 实现离线访问、推送通知等高级功能。
二、PWA 的核心优势与好处
1. 可靠性
- 离线可用:通过 Service Workers 缓存关键资源,即使无网络连接也能加载内容。
- 快速响应:首次加载后,后续访问速度接近即时,减少用户等待时间。
2. 性能优化
- 资源预缓存:Service Workers 提前加载核心资源,降低网络依赖;
- 智能更新:仅更新变动内容,避免重复下载完整应用。
3. 跨平台兼容性
- 全设备适配:支持桌面、手机、平板等设备,一次开发多端覆盖;
- 响应式设计:自动适配不同屏幕尺寸,提供一致的视觉体验。
4. 用户粘性与推广优势
- 推送通知:通过浏览器向用户发送实时提醒,提升用户活跃度;
- 免安装推广:用户可直接通过 URL 访问,无需应用商店审核;
- SEO 友好:内容可被搜索引擎索引,提高自然流量转化率。
三、为何选择 PWA?
1. 用户体验升级
- 消除原生应用下载门槛,用户点击链接即可使用完整功能;
- 提供类原生应用的交互体验(如全屏模式、主屏图标)。
2. 开发与维护成本降低
- 统一代码库:无需为不同平台单独开发,节省人力与时间;
- 简化更新流程:服务端更新自动同步到客户端,无需用户手动操作7。
3. 适应多样化场景
- 弱网/离线场景:如教育、电商等领域的离线内容访问;
- 轻量化需求:替代低频使用的原生应用,减少设备存储压力。
四、开发
以下示例架构环境是 vite + react 脚手架。
1. 安装PWA
npm i vite-plugin-pwa -D
2. vite 配置
import { VitePWA } from 'vite-plugin-pwa'
// https://vite.dev/config/
export default defineConfig({
plugins: [
react(),
VitePWA({
registerType: 'autoUpdate',
workbox: {
globPatterns: ['**/*.{js,css,html}'],
},
manifest: {
name: '源码分享',
short_name: '源码分享',
description: '源码分享',
theme_color: '#000000',
background_color: '#000000',
icons: [
{
src: 'public/logo.svg',
sizes: '192x192',
type: 'image/svg+xml',
},
{
src: 'public/logo.svg',
sizes: '512x512',
type: 'image/svg+xml',
},
],
},
devOptions: {
enabled: true,
type: 'module',
},
}),
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
})
配置注意:
- icons 图标的实际大小必须大于 sizes 的设置值。192×192:适配移动端设备主屏幕图标;512×512:用于桌面端安装弹窗及 Splash 屏幕
- icons 推荐使用svg图标
- devOptions 配置本地开发环境。没有设置浏览器不会出现安装应用的入口。
到此依赖、配置都已经全部完成,是不是非常简单。
3. 使用
首页来分析一下具体需要实现的需求,希望做些什么功能。其实上面配置好,个人觉得90%目的已经达到。能够安装应用,生成一个渐进式 Web 应用(PWA),并缓存关键资源。
下面我们来分析一些高级的运用、体验的优化。
如何引导用户安装PWA应用?
- 捕获安装事件
let deferredPrompt = null;
const handleBeforeInstallPrompt = (e) => {
e.preventDefault();
deferredPrompt.current = e;
setIsInstallable(true);
};
window.addEventListener("beforeinstallprompt", handleBeforeInstallPrompt);
- 检测已安装状态
const checkDisplayMode = () => {
const isStandalone = window.matchMedia(
"(display-mode: standalone)"
).matches;
const isIOS =
/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
setIsInstalled(isStandalone || (isIOS && navigator.standalone));
};
注意:iOS 不支持 beforeinstallprompt
事件,需通过 navigator.standalone
检测
- 页面引导提交用户安装
最后就是如何更好的引导用户安装,这里不多说了,自由发挥自己的引导方式,做更好的ui效果。
完整源码
import { useEffect, useState, useRef } from 'react';
function App() {
const [isInstallable, setIsInstallable] = useState(false);
const [isInstalled, setIsInstalled] = useState(false);
const deferredPrompt = useRef(null);
useEffect(() => {
const handleBeforeInstallPrompt = (e) => {
e.preventDefault();
deferredPrompt.current = e;
setIsInstallable(true);
};
window.addEventListener("beforeinstallprompt", handleBeforeInstallPrompt);
// 当前是否已是pwa离线应用
const checkDisplayMode = () => {
const isStandalone = window.matchMedia(
"(display-mode: standalone)"
).matches;
const isIOS =
/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
setIsInstalled(isStandalone || (isIOS && navigator.standalone));
};
checkDisplayMode();
return () => {
window.removeEventListener(
"beforeinstallprompt",
handleBeforeInstallPrompt
);
};
}, []);
const handleInstall = async () => {
if (deferredPrompt.current) {
deferredPrompt.current.prompt();
const { outcome } = await deferredPrompt.current.userChoice;
if (outcome === 'accepted') {
// 同意
setIsInstallable(false);
deferredPrompt.current = null;
} else {
// 拒绝
console.log("拒绝");
}
}
};
return (
<>
<div className="container mt-5">
<button
className="px-4 py-2 bg-blue-500 text-white rounded-lg
transition-colors duration-200
hover:bg-blue-600 hover:shadow-md
focus:outline-none focus:ring-2 focus:ring-blue-500
disabled:bg-blue-300 disabled:text-gray-100 disabled:cursor-not-allowed"
onClick={handleInstall}
disabled={!isInstallable}
>
{isInstalled ? "已安装" : isInstallable ? "安装" : "已安装"}
</button>
</div>
</>
);
}
export default App;
最后PWA上线的必须条件:
- 生产环境需部署 SSL 证书
- 响应式设计(确保页面适配不同设备尺寸)
预览

原文链接:https://code.ifrontend.net/archives/290,转载请注明出处。
评论0