使用 PWA(Progressive Web App) 构建一个 Three.js 案例,可以让你创建一个具有离线功能、快速加载和原生应用体验的 3D 网页应用。以下是详细的步骤和代码示例,帮助你实现这一目标。
1. PWA 简介
PWA 是一种现代网页技术,通过 Service Worker、Web App Manifest 等技术,使网页应用具备以下特性:
- 离线访问:通过缓存资源,用户可以在没有网络的情况下访问应用。
- 快速加载:通过预缓存和资源优化,提升加载速度。
- 原生体验:可以添加到主屏幕,像原生应用一样运行。
2. 项目结构
我们将创建一个简单的 Three.js PWA 项目,项目结构如下:
/threejs-pwa
├── index.html
├── styles.css
├── main.js
├── service-worker.js
├── manifest.json
└── assets
├── icon-192x192.png
└── icon-512x512.png
3. 实现步骤
3.1 创建 HTML 文件
在 index.html
中引入 Three.js 库,并设置 PWA 的基本结构。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Three.js PWA</title>
<link rel="stylesheet" href="styles.css">
<link rel="manifest" href="manifest.json">
</head>
<body>
<div id="container"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r146/three.min.js"></script>
<script src="main.js"></script>
<script>
// 注册 Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js')
.then(() => console.log('Service Worker 注册成功'))
.catch(err => console.error('Service Worker 注册失败:', err));
}
</script>
</body>
</html>
3.2 创建 CSS 文件
在 styles.css
中设置页面样式,确保 3D 场景填满整个屏幕。
body, html {
margin: 0;
padding: 0;
overflow: hidden;
height: 100%;
}
#container {
width: 100%;
height: 100%;
}
3.3 创建 Three.js 场景
在 main.js
中编写 Three.js 代码,创建一个简单的 3D 场景。
// 场景
const scene = new THREE.Scene();
// 相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
// 渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('container').appendChild(renderer.domElement);
// 立方体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 动画循环
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
// 窗口大小调整
window.addEventListener('resize', () => {
const width = window.innerWidth;
const height = window.innerHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
});
3.4 创建 Service Worker
在 service-worker.js
中编写 Service Worker 代码,用于缓存资源和实现离线功能。
const CACHE_NAME = 'threejs-pwa-v1';
const ASSETS_TO_CACHE = [
'/',
'/index.html',
'/styles.css',
'/main.js',
'https://cdnjs.cloudflare.com/ajax/libs/three.js/r146/three.min.js'
];
// 安装 Service Worker
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => cache.addAll(ASSETS_TO_CACHE))
.then(() => self.skipWaiting())
);
});
// 拦截网络请求
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => response || fetch(event.request))
);
});
// 激活 Service Worker
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
}).then(() => self.clients.claim())
);
});
3.5 创建 Web App Manifest
在 manifest.json
中定义应用的元数据,使其可以添加到主屏幕。
{
"short_name": "ThreePWA",
"name": "Three.js PWA",
"icons": [
{
"src": "assets/icon-192x192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "assets/icon-512x512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/",
"background_color": "#ffffff",
"display": "standalone",
"scope": "/",
"theme_color": "#000000"
}
3.6 添加应用图标
将应用图标(icon-192x192.png
和 icon-512x512.png
)放入 assets
文件夹中。
4. 运行项目
- 将项目部署到支持 HTTPS 的服务器(PWA 必须运行在 HTTPS 环境下)。
- 打开浏览器访问应用。
- 浏览器会提示“添加到主屏幕”,点击后应用会像原生应用一样运行。
5. 测试离线功能
- 打开应用并等待 Service Worker 缓存资源。
- 关闭网络连接,刷新页面。
- 应用仍然可以正常运行,因为资源已被缓存。
6. 总结
通过以上步骤,我们成功构建了一个基于 Three.js 的 PWA 应用。它具备以下特性:
- 离线访问:通过 Service Worker 缓存资源。
- 快速加载:通过预缓存和资源优化。
- 原生体验:可以添加到主屏幕,像原生应用一样运行。
你可以在此基础上进一步扩展功能,例如:
- 加载复杂的 3D 模型。
- 添加交互功能(如点击、拖拽)。
- 使用 WebXR 实现 VR/AR 效果。
希望这篇教程对你有所帮助!如果你有任何问题,欢迎在评论区留言讨论。
注:如若尝试失败不妨前往博主GitHub仓库查看源代码。