PWA渐进式应用

PWA概述

PWA(Progressive Web App)是一种Web应用,使用现代Web技术提供类似原生应用的体验。

东巴文(db-w.cn) 认为:PWA是Web应用的未来,它结合了Web和原生应用的优势,提供了离线工作、推送通知、添加到主屏幕等功能,是现代Web开发的重要方向。

PWA特性

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PWA概述 - 东巴文</title>
    
    <style>
        body {
            font-family: 'Segoe UI', sans-serif;
            padding: 20px;
            background: #f5f5f5;
        }
        
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
        }
        
        h1 {
            color: #667eea;
            margin-bottom: 20px;
        }
        
        h2 {
            color: #764ba2;
            margin: 30px 0 15px;
            border-left: 4px solid #764ba2;
            padding-left: 15px;
        }
        
        .pwa-demo {
            background: #f8f9fa;
            padding: 20px;
            border: 2px solid #ddd;
            margin: 15px 0;
            border-radius: 10px;
        }
        
        .pwa-demo h3 {
            color: #667eea;
            margin-bottom: 10px;
        }
        
        .feature-list {
            list-style: none;
            padding: 0;
        }
        
        .feature-list li {
            padding: 8px 0;
            border-bottom: 1px solid #eee;
        }
        
        .feature-list li:before {
            content: "✓ ";
            color: #667eea;
            font-weight: bold;
        }
        
        .feature-table {
            width: 100%;
            border-collapse: collapse;
            margin: 20px 0;
        }
        
        .feature-table th,
        .feature-table td {
            padding: 12px;
            text-align: left;
            border: 1px solid #ddd;
        }
        
        .feature-table th {
            background: #667eea;
            color: white;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>PWA概述</h1>
        
        <h2>什么是PWA</h2>
        
        <div class="pwa-demo">
            <h3>核心概念</h3>
            <p>PWA(Progressive Web App)是一种使用现代Web技术构建的应用,提供类似原生应用的体验。它具有以下特点:</p>
            
            <ul class="feature-list">
                <li><strong>渐进式:</strong> 适用于所有浏览器,渐进增强用户体验</li>
                <li><strong>响应式:</strong> 适合任何设备:桌面、手机、平板</li>
                <li><strong>离线工作:</strong> 使用Service Worker支持离线功能</li>
                <li><strong>类原生应用:</strong> 感觉像原生应用,交互流畅</li>
                <li><strong>安全:</strong> 通过HTTPS提供服务,确保安全</li>
                <li><strong>可发现:</strong> 可被搜索引擎识别,SEO友好</li>
                <li><strong>可安装:</strong> 可添加到主屏幕,无需应用商店</li>
                <li><strong>可链接:</strong> 通过URL分享,无需安装</li>
            </ul>
        </div>
        
        <h2>PWA核心功能</h2>
        
        <table class="feature-table">
            <thead>
                <tr>
                    <th>功能</th>
                    <th>技术</th>
                    <th>作用</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td><strong>离线工作</strong></td>
                    <td>Service Worker</td>
                    <td>缓存资源,离线访问</td>
                </tr>
                <tr>
                    <td><strong>推送通知</strong></td>
                    <td>Push API</td>
                    <td>推送消息,提高用户参与度</td>
                </tr>
                <tr>
                    <td><strong>后台同步</strong></td>
                    <td>Background Sync API</td>
                    <td>后台同步数据</td>
                </tr>
                <tr>
                    <td><strong>添加到主屏幕</strong></td>
                    <td>Web App Manifest</td>
                    <td>安装应用,全屏运行</td>
                </tr>
                <tr>
                    <td><strong>支付</strong></td>
                    <td>Payment Request API</td>
                    <td>原生支付体验</td>
                </tr>
                <tr>
                    <td><strong>凭证管理</strong></td>
                    <td>Credential Management API</td>
                    <td>自动登录</td>
                </tr>
            </tbody>
        </table>
        
        <h2>PWA优势</h2>
        
        <div class="pwa-demo">
            <h3>与传统Web应用对比</h3>
            <div style="background: #2d2d2d; color: #f8f8f2; padding: 15px; border-radius: 5px; margin: 10px 0;">
                <pre>
传统Web应用:
- 需要网络连接
- 无法离线访问
- 无法推送通知
- 无法添加到主屏幕
- 加载速度慢
- 用户体验差

PWA:
- 支持离线工作
- 可推送通知
- 可添加到主屏幕
- 加载速度快
- 类原生应用体验
- SEO友好
- 跨平台
- 无需应用商店审核
                </pre>
            </div>
        </div>
        
        <h2>PWA示例</h2>
        
        <div class="pwa-demo">
            <h3>基本结构</h3>
            <div style="background: #2d2d2d; color: #f8f8f2; padding: 15px; border-radius: 5px; margin: 10px 0;">
                <pre>
&lt;!DOCTYPE html&gt;
&lt;html lang="zh-CN"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    
    &lt;!-- PWA Meta标签 --&gt;
    &lt;meta name="theme-color" content="#667eea"&gt;
    &lt;meta name="description" content="我的PWA应用"&gt;
    &lt;meta name="apple-mobile-web-app-capable" content="yes"&gt;
    &lt;meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"&gt;
    &lt;meta name="apple-mobile-web-app-title" content="我的PWA"&gt;
    
    &lt;!-- Web App Manifest --&gt;
    &lt;link rel="manifest" href="/manifest.json"&gt;
    
    &lt;!-- 图标 --&gt;
    &lt;link rel="icon" type="image/png" href="/icons/icon-192.png"&gt;
    &lt;link rel="apple-touch-icon" href="/icons/icon-192.png"&gt;
    
    &lt;title&gt;我的PWA&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;!-- 应用内容 --&gt;
    
    &lt;script&gt;
        // 注册Service Worker
        if ('serviceWorker' in navigator) {
            window.addEventListener('load', () =&gt; {
                navigator.serviceWorker.register('/sw.js')
                    .then(registration =&gt; {
                        console.log('Service Worker注册成功:', registration.scope);
                    })
                    .catch(error =&gt; {
                        console.error('Service Worker注册失败:', error);
                    });
            });
        }
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
                </pre>
            </div>
        </div>
        
        <div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
            <strong>东巴文提示:</strong>PWA是现代Web应用的重要方向。掌握Service Worker、Web App Manifest、Push API等核心技术,能构建出体验优秀的渐进式Web应用,提供类原生应用的用户体验。
        </div>
    </div>
</body>
</html>

Service Worker

Service Worker是PWA的核心,提供了离线缓存、推送通知、后台同步等功能。

Service Worker基础

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Service Worker - 东巴文</title>
    
    <style>
        body {
            font-family: 'Segoe UI', sans-serif;
            padding: 20px;
            background: #f5f5f5;
        }
        
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
        }
        
        h1 {
            color: #667eea;
            margin-bottom: 20px;
        }
        
        h2 {
            color: #764ba2;
            margin: 30px 0 15px;
            border-left: 4px solid #764ba2;
            padding-left: 15px;
        }
        
        .sw-demo {
            background: #f8f9fa;
            padding: 20px;
            border: 2px solid #ddd;
            margin: 15px 0;
            border-radius: 10px;
        }
        
        .sw-demo h3 {
            color: #667eea;
            margin-bottom: 10px;
        }
        
        .code-block {
            background: #2d2d2d;
            color: #f8f8f2;
            padding: 15px;
            border-radius: 5px;
            overflow-x: auto;
            margin: 10px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Service Worker</h1>
        
        <h2>注册Service Worker</h2>
        
        <div class="sw-demo">
            <h3>注册代码</h3>
            <div class="code-block">
                <pre>
// 检查浏览器支持
if ('serviceWorker' in navigator) {
    window.addEventListener('load', () =&gt; {
        navigator.serviceWorker.register('/sw.js')
            .then(registration =&gt; {
                console.log('Service Worker注册成功:', registration.scope);
                
                // 检查更新
                registration.addEventListener('updatefound', () =&gt; {
                    const newWorker = registration.installing;
                    newWorker.addEventListener('statechange', () =&gt; {
                        if (newWorker.state === 'installed' &amp;&amp; navigator.serviceWorker.controller) {
                            // 新版本可用
                            console.log('新版本可用,请刷新页面');
                        }
                    });
                });
            })
            .catch(error =&gt; {
                console.error('Service Worker注册失败:', error);
            });
    });
    
    // 监听Service Worker更新
    navigator.serviceWorker.addEventListener('controllerchange', () =&gt; {
        console.log('Service Worker已更新');
    });
}
                </pre>
            </div>
        </div>
        
        <h2>Service Worker生命周期</h2>
        
        <div class="sw-demo">
            <h3>生命周期事件</h3>
            <div class="code-block">
                <pre>
// sw.js - Service Worker文件

const CACHE_NAME = 'my-pwa-v1';
const urlsToCache = [
    '/',
    '/styles/main.css',
    '/scripts/main.js',
    '/images/logo.png'
];

// 安装事件
self.addEventListener('install', event =&gt; {
    console.log('Service Worker安装中...');
    
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then(cache =&gt; {
                console.log('缓存已打开');
                return cache.addAll(urlsToCache);
            })
            .then(() =&gt; {
                console.log('所有资源已缓存');
                return self.skipWaiting(); // 跳过等待,立即激活
            })
    );
});

// 激活事件
self.addEventListener('activate', event =&gt; {
    console.log('Service Worker激活中...');
    
    event.waitUntil(
        caches.keys().then(cacheNames =&gt; {
            return Promise.all(
                cacheNames.map(cacheName =&gt; {
                    if (cacheName !== CACHE_NAME) {
                        console.log('删除旧缓存:', cacheName);
                        return caches.delete(cacheName);
                    }
                })
            );
        }).then(() =&gt; {
            console.log('Service Worker已激活');
            return self.clients.claim(); // 立即控制所有客户端
        })
    );
});

// 拦截请求
self.addEventListener('fetch', event =&gt; {
    event.respondWith(
        caches.match(event.request)
            .then(response =&gt; {
                // 缓存命中,返回缓存
                if (response) {
                    return response;
                }
                
                // 否则,从网络获取
                return fetch(event.request).then(response =&gt; {
                    // 检查是否是有效响应
                    if (!response || response.status !== 200 || response.type !== 'basic') {
                        return response;
                    }
                    
                    // 克隆响应
                    const responseToCache = response.clone();
                    
                    // 缓存新资源
                    caches.open(CACHE_NAME)
                        .then(cache =&gt; {
                            cache.put(event.request, responseToCache);
                        });
                    
                    return response;
                });
            })
    );
});
                </pre>
            </div>
        </div>
        
        <h2>缓存策略</h2>
        
        <div class="sw-demo">
            <h3>常用缓存策略</h3>
            <div class="code-block">
                <pre>
// 1. 缓存优先(Cache First)
// 适用于不常变化的静态资源
self.addEventListener('fetch', event =&gt; {
    event.respondWith(
        caches.match(event.request)
            .then(response =&gt; {
                return response || fetch(event.request);
            })
    );
});

// 2. 网络优先(Network First)
// 适用于需要最新数据的动态内容
self.addEventListener('fetch', event =&gt; {
    event.respondWith(
        fetch(event.request)
            .then(response =&gt; {
                // 缓存响应
                const responseClone = response.clone();
                caches.open(CACHE_NAME).then(cache =&gt; {
                    cache.put(event.request, responseClone);
                });
                return response;
            })
            .catch(() =&gt; {
                // 网络失败,返回缓存
                return caches.match(event.request);
            })
    );
});

// 3. 网络优先,缓存降级(Stale While Revalidate)
// 快速响应,后台更新
self.addEventListener('fetch', event =&gt; {
    event.respondWith(
        caches.match(event.request).then(cachedResponse =&gt; {
            const fetchPromise = fetch(event.request).then(networkResponse =&gt; {
                // 更新缓存
                caches.open(CACHE_NAME).then(cache =&gt; {
                    cache.put(event.request, networkResponse.clone());
                });
                return networkResponse;
            });
            
            // 返回缓存或网络响应
            return cachedResponse || fetchPromise;
        })
    );
});

// 4. 仅缓存(Cache Only)
// 适用于完全静态的资源
self.addEventListener('fetch', event =&gt; {
    event.respondWith(caches.match(event.request));
});

// 5. 仅网络(Network Only)
// 适用于必须实时的数据
self.addEventListener('fetch', event =&gt; {
    event.respondWith(fetch(event.request));
});
                </pre>
            </div>
        </div>
        
        <h2>离线页面</h2>
        
        <div class="sw-demo">
            <h3>离线回退</h3>
            <div class="code-block">
                <pre>
// 缓存离线页面
const OFFLINE_URL = '/offline.html';

self.addEventListener('install', event =&gt; {
    event.waitUntil(
        caches.open(CACHE_NAME).then(cache =&gt; {
            return cache.addAll([
                '/',
                OFFLINE_URL
            ]);
        })
    );
});

// 拦截导航请求
self.addEventListener('fetch', event =&gt; {
    if (event.request.mode === 'navigate') {
        event.respondWith(
            fetch(event.request)
                .catch(() =&gt; {
                    return caches.match(OFFLINE_URL);
                })
        );
    }
});

// offline.html
/*
&lt;!DOCTYPE html&gt;
&lt;html lang="zh-CN"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;title&gt;离线 - 我的PWA&lt;/title&gt;
    &lt;style&gt;
        body {
            font-family: 'Segoe UI', sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            background: #f5f5f5;
        }
        
        .offline {
            text-align: center;
            padding: 40px;
            background: white;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        h1 {
            color: #667eea;
            margin-bottom: 10px;
        }
        
        p {
            color: #666;
            margin-bottom: 20px;
        }
        
        button {
            padding: 10px 20px;
            background: #667eea;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class="offline"&gt;
        &lt;h1&gt;你离线了&lt;/h1&gt;
        &lt;p&gt;请检查网络连接后重试&lt;/p&gt;
        &lt;button onclick="location.reload()"&gt;重试&lt;/button&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
*/
                </pre>
            </div>
        </div>
        
        <div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
            <strong>东巴文提示:</strong>Service Worker是PWA的核心技术,提供了离线缓存、请求拦截、推送通知等功能。掌握生命周期、缓存策略、离线处理,能构建出体验优秀的PWA应用。
        </div>
    </div>
</body>
</html>

Web App Manifest

Web App Manifest是一个JSON文件,描述了PWA的元数据,如名称、图标、启动画面等。

Manifest配置

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web App Manifest - 东巴文</title>
    
    <style>
        body {
            font-family: 'Segoe UI', sans-serif;
            padding: 20px;
            background: #f5f5f5;
        }
        
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
        }
        
        h1 {
            color: #667eea;
            margin-bottom: 20px;
        }
        
        h2 {
            color: #764ba2;
            margin: 30px 0 15px;
            border-left: 4px solid #764ba2;
            padding-left: 15px;
        }
        
        .manifest-demo {
            background: #f8f9fa;
            padding: 20px;
            border: 2px solid #ddd;
            margin: 15px 0;
            border-radius: 10px;
        }
        
        .manifest-demo h3 {
            color: #667eea;
            margin-bottom: 10px;
        }
        
        .code-block {
            background: #2d2d2d;
            color: #f8f8f2;
            padding: 15px;
            border-radius: 5px;
            overflow-x: auto;
            margin: 10px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Web App Manifest</h1>
        
        <h2>Manifest文件</h2>
        
        <div class="manifest-demo">
            <h3>manifest.json</h3>
            <div class="code-block">
                <pre>
{
    "name": "我的PWA应用",
    "short_name": "我的PWA",
    "description": "这是一个渐进式Web应用示例",
    "start_url": "/",
    "display": "standalone",
    "background_color": "#ffffff",
    "theme_color": "#667eea",
    "orientation": "portrait-primary",
    "scope": "/",
    "lang": "zh-CN",
    "dir": "ltr",
    "categories": ["productivity", "utilities"],
    "icons": [
        {
            "src": "/icons/icon-72.png",
            "sizes": "72x72",
            "type": "image/png",
            "purpose": "maskable any"
        },
        {
            "src": "/icons/icon-96.png",
            "sizes": "96x96",
            "type": "image/png"
        },
        {
            "src": "/icons/icon-128.png",
            "sizes": "128x128",
            "type": "image/png"
        },
        {
            "src": "/icons/icon-144.png",
            "sizes": "144x144",
            "type": "image/png"
        },
        {
            "src": "/icons/icon-152.png",
            "sizes": "152x152",
            "type": "image/png"
        },
        {
            "src": "/icons/icon-192.png",
            "sizes": "192x192",
            "type": "image/png"
        },
        {
            "src": "/icons/icon-384.png",
            "sizes": "384x384",
            "type": "image/png"
        },
        {
            "src": "/icons/icon-512.png",
            "sizes": "512x512",
            "type": "image/png"
        }
    ],
    "screenshots": [
        {
            "src": "/screenshots/screenshot1.png",
            "sizes": "1280x720",
            "type": "image/png"
        }
    ],
    "shortcuts": [
        {
            "name": "新建",
            "short_name": "新建",
            "description": "创建新内容",
            "url": "/new",
            "icons": [
                {
                    "src": "/icons/new.png",
                    "sizes": "96x96"
                }
            ]
        },
        {
            "name": "搜索",
            "short_name": "搜索",
            "description": "搜索内容",
            "url": "/search",
            "icons": [
                {
                    "src": "/icons/search.png",
                    "sizes": "96x96"
                }
            ]
        }
    ],
    "related_applications": [
        {
            "platform": "play",
            "url": "https://play.google.com/store/apps/details?id=com.example.app"
        }
    ],
    "prefer_related_applications": false
}
                </pre>
            </div>
        </div>
        
        <h2>Manifest属性</h2>
        
        <div class="manifest-demo">
            <h3>主要属性说明</h3>
            <div class="code-block">
                <pre>
// 基本属性
{
    // 应用名称
    "name": "我的PWA应用",           // 完整名称
    "short_name": "我的PWA",         // 短名称,显示在主屏幕
    
    // 描述
    "description": "应用描述",
    
    // 启动URL
    "start_url": "/",               // 启动时加载的URL
    "scope": "/",                   // 应用范围
    
    // 显示模式
    "display": "standalone",        // fullscreen | standalone | minimal-ui | browser
    
    // 方向
    "orientation": "portrait-primary", // portrait | landscape | any
    
    // 主题颜色
    "theme_color": "#667eea",       // 主题颜色
    "background_color": "#ffffff",  // 启动画面背景色
    
    // 语言
    "lang": "zh-CN",
    "dir": "ltr"                    // ltr | rtl
}

// 显示模式说明
/*
fullscreen:    全屏模式,隐藏所有浏览器UI
standalone:    独立应用模式,像原生应用
minimal-ui:    最小UI模式,保留基本浏览器控件
browser:       浏览器模式,传统网页
*/

// 图标要求
/*
必须提供:
- 192x192: Android Chrome要求
- 512x512: Android Chrome要求
- 180x180: iOS要求

推荐提供:
- 72x72, 96x96, 128x128, 144x144, 152x152, 384x384

purpose:
- any: 任何用途
- maskable: 可遮罩图标(Android自适应图标)
*/
                </pre>
            </div>
        </div>
        
        <h2>在HTML中引用</h2>
        
        <div class="manifest-demo">
            <h3>HTML配置</h3>
            <div class="code-block">
                <pre>
&lt;!DOCTYPE html&gt;
&lt;html lang="zh-CN"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    
    &lt;!-- 引用Manifest --&gt;
    &lt;link rel="manifest" href="/manifest.json"&gt;
    
    &lt;!-- 主题颜色 --&gt;
    &lt;meta name="theme-color" content="#667eea"&gt;
    
    &lt;!-- iOS支持 --&gt;
    &lt;meta name="apple-mobile-web-app-capable" content="yes"&gt;
    &lt;meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"&gt;
    &lt;meta name="apple-mobile-web-app-title" content="我的PWA"&gt;
    
    &lt;!-- iOS图标 --&gt;
    &lt;link rel="apple-touch-icon" href="/icons/icon-192.png"&gt;
    &lt;link rel="apple-touch-icon" sizes="152x152" href="/icons/icon-152.png"&gt;
    &lt;link rel="apple-touch-icon" sizes="180x180" href="/icons/icon-180.png"&gt;
    &lt;link rel="apple-touch-icon" sizes="167x167" href="/icons/icon-167.png"&gt;
    
    &lt;!-- Windows Tiles --&gt;
    &lt;meta name="msapplication-TileImage" content="/icons/icon-144.png"&gt;
    &lt;meta name="msapplication-TileColor" content="#667eea"&gt;
    
    &lt;title&gt;我的PWA&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;!-- 应用内容 --&gt;
&lt;/body&gt;
&lt;/html&gt;
                </pre>
            </div>
        </div>
        
        <h2>安装提示</h2>
        
        <div class="manifest-demo">
            <h3>自定义安装提示</h3>
            <div class="code-block">
                <pre>
let deferredPrompt;

window.addEventListener('beforeinstallprompt', (e) =&gt; {
    // 阻止默认提示
    e.preventDefault();
    
    // 保存事件
    deferredPrompt = e;
    
    // 显示自定义安装按钮
    showInstallButton();
});

function showInstallButton() {
    const installButton = document.createElement('button');
    installButton.textContent = '安装应用';
    installButton.style.cssText = `
        position: fixed;
        bottom: 20px;
        right: 20px;
        padding: 15px 30px;
        background: #667eea;
        color: white;
        border: none;
        border-radius: 10px;
        cursor: pointer;
        box-shadow: 0 4px 10px rgba(0,0,0,0.2);
        z-index: 1000;
    `;
    
    installButton.addEventListener('click', async () =&gt; {
        // 显示安装提示
        deferredPrompt.prompt();
        
        // 等待用户响应
        const { outcome } = await deferredPrompt.userChoice;
        
        console.log(`用户选择: ${outcome}`);
        
        // 清除引用
        deferredPrompt = null;
        
        // 移除按钮
        installButton.remove();
    });
    
    document.body.appendChild(installButton);
}

// 监听安装成功事件
window.addEventListener('appinstalled', (e) =&gt; {
    console.log('应用已安装');
});
                </pre>
            </div>
        </div>
        
        <div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
            <strong>东巴文提示:</strong>Web App Manifest是PWA的重要组成部分,定义了应用的元数据和安装信息。正确配置manifest.json,能提供良好的安装体验和启动画面,让PWA更像原生应用。
        </div>
    </div>
</body>
</html>

学习检验

完成本章学习后,请尝试回答以下问题:

  1. 选择题: PWA的核心技术是什么?

    • A. Service Worker, Web App Manifest, HTTPS
    • B. HTML, CSS, JavaScript
    • C. React, Vue, Angular
    • D. Webpack, Vite, Parcel
  2. 填空题: Service Worker的生命周期包括____、____和____三个阶段。

  3. 简答题: PWA相比传统Web应用有哪些优势?

  4. 实践题: 创建一个简单的PWA应用,要求:

    • 注册Service Worker
    • 配置Web App Manifest
    • 实现离线访问
    • 支持添加到主屏幕
  5. 应用题: 分析一个知名PWA应用(如Twitter Lite、Starbucks),总结其PWA特性实现方式。