各位乡亲,我是老王,咱村口开了个民宿,这年头也得赶赶时髦,琢磨着怎么用点新技术,让大伙住得更舒坦。最近听说个叫 PWA 的玩意儿,说是能让手机像 App 一样用,还能离线用!这不,我就琢磨着,能不能用这 PWA 里的 Service Worker,把咱民宿搞得更洋气,让大伙儿没网也能看房订房?
一、啥是 Service Worker?能帮咱民宿干啥?
Service Worker,简单说,就像个在浏览器后台默默干活的“服务员”。它能拦截网络请求,缓存网页内容,还能在没网的时候,直接把缓存的内容拿出来用。这对于咱这种乡下民宿来说,简直是救星!
你想啊,来咱这儿玩的,不少都是城里人,手机信号不见得一直满格。有了 Service Worker,他们就能:
- 离线浏览民宿介绍: 就算没网,也能看到咱民宿的照片、房型介绍、价格等等,心里有个数。
- 离线预订房间: 没网也能填写预订信息,等有网了,自动提交,方便!
- 离线查看用户评价: 看看住过的人怎么说,心里更有底。
二、Service Worker 咋实现离线民宿介绍?
这块儿是重点,我得好好琢磨琢磨。咱得先让 Service Worker 把民宿介绍相关的网页内容缓存起来。
- 注册 Service Worker:
在咱民宿的网页里,加一段 JavaScript 代码,让浏览器知道有这么个“服务员”要来上班。
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}).catch(function(err) {
console.log('ServiceWorker registration failed: ', err);
});
}
这段代码的意思是,如果浏览器支持 Service Worker,就注册一个叫 /sw.js
的文件,这个文件就是咱的 Service Worker 的代码。
- 编写 Service Worker 代码(sw.js):
这个文件是 Service Worker 的核心,咱得告诉它,哪些东西要缓存,没网的时候怎么处理。
// 缓存的名字
var CACHE_NAME = '民宿介绍-v1';
// 需要缓存的文件
var urlsToCache = [
'/', // 首页
'/index.html', // 首页 HTML
'/css/style.css', // 样式文件
'/js/main.js', // JavaScript 文件
'/images/logo.png', // Logo 图片
'/images/room1.jpg', // 房间图片
'/images/room2.jpg', // 房间图片
// ... 更多图片和资源
];
// 安装 Service Worker
self.addEventListener('install', function(event) {
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
// 拦截网络请求
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
// Not in cache - return fetch request
return fetch(event.request);
})
);
});
// 更新 Service Worker
self.addEventListener('activate', function(event) {
var cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
这段代码有点长,我来解释一下:
CACHE_NAME
:缓存的名字,每次更新内容,可以改一下这个名字,浏览器就会重新缓存。urlsToCache
:需要缓存的文件列表,把咱民宿网页用到的 HTML、CSS、JavaScript、图片等等都加进去。install
事件:Service Worker 安装的时候,会执行这段代码,把urlsToCache
里的文件都缓存起来。fetch
事件:每次浏览器发起网络请求,都会经过这里。Service Worker 会先在缓存里找,找到了就直接返回缓存的内容,没找到就发起真正的网络请求。activate
事件:Service Worker 更新的时候,会执行这段代码,把旧的缓存清理掉。
- 测试离线访问:
把这些代码都放到咱民宿的网站上,然后用手机访问一下。第一次访问的时候,Service Worker 会把需要缓存的文件都下载下来。然后,断开手机的网络,再访问一次,看看是不是还能正常浏览民宿介绍?如果能,那就说明成功了!
三、Service Worker 咋实现离线预订房间和自动同步?
光能看还不够,还得能订!这块儿稍微复杂点,咱得用到一些技巧。
- 离线存储预订信息:
没网的时候,用户填写的预订信息,咱得先存在手机里。可以用 localStorage
或者 IndexedDB
来存储。
localStorage
比较简单,适合存储少量数据。IndexedDB
比较复杂,但能存储大量数据,也更可靠。
我建议咱用 IndexedDB
,毕竟预订信息比较重要,不能随便丢。
// 打开数据库
var dbPromise = idb.open('民宿预订', 1, function(db) {
if (!db.objectStoreNames.contains('预订信息')) {
db.createObjectStore('预订信息', { keyPath: 'id', autoIncrement: true });
}
});
// 存储预订信息
function saveBooking(bookingData) {
return dbPromise.then(function(db) {
var tx = db.transaction('预订信息', 'readwrite');
var store = tx.objectStore('预订信息');
store.put(bookingData);
return tx.complete;
});
}
// 获取所有未同步的预订信息
function getUnsyncedBookings() {
return dbPromise.then(function(db) {
var tx = db.transaction('预订信息', 'readonly');
var store = tx.objectStore('预订信息');
return store.getAll();
});
}
这段代码用了 idb
这个库,是对 IndexedDB
的封装,用起来更方便。主要做了这几件事:
- 打开一个叫“民宿预订”的数据库。
- 创建一个叫“预订信息”的表,用来存储预订信息。
saveBooking
函数:把预订信息存到数据库里。getUnsyncedBookings
函数:获取所有未同步的预订信息。
- 监听网络状态:
一旦网络恢复,咱就得自动把离线存储的预订信息提交到服务器。
window.addEventListener('online', function(event) {
console.log('网络已恢复,开始同步预订信息...');
syncBookings();
});
function syncBookings() {
getUnsyncedBookings().then(function(bookings) {
bookings.forEach(function(booking) {
// 发送预订信息到服务器
fetch('/api/bookings', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(booking)
}).then(function(response) {
if (response.ok) {
// 同步成功,删除本地存储的预订信息
deleteBooking(booking.id);
} else {
console.error('预订信息同步失败:', response.status);
}
});
});
});
}
function deleteBooking(id) {
return dbPromise.then(function(db) {
var tx = db.transaction('预订信息', 'readwrite');
var store = tx.objectStore('预订信息');
store.delete(id);
return tx.complete;
});
}
这段代码做了这几件事:
- 监听
online
事件,当网络恢复的时候,就执行syncBookings
函数。 syncBookings
函数:获取所有未同步的预订信息,然后逐个发送到服务器。- 如果服务器返回成功,就删除本地存储的预订信息。
- 服务器端处理:
服务器端需要提供一个 /api/bookings
接口,用来接收客户端提交的预订信息,并保存到数据库里。
四、离线用户评价咋搞?
用户评价也挺重要,能让其他游客更了解咱民宿。这块儿跟离线预订房间类似,也需要用到离线存储和自动同步。
- 离线存储用户评价:
没网的时候,用户填写的评价信息,咱也得先存在手机里,可以用 IndexedDB
。
- 监听网络状态:
一旦网络恢复,咱就得自动把离线存储的评价信息提交到服务器。
- 服务器端处理:
服务器端需要提供一个 /api/reviews
接口,用来接收客户端提交的评价信息,并保存到数据库里。
五、多语言支持咋实现?
现在来咱这儿玩的,外国人也越来越多了,咱还得考虑多语言支持。这块儿可以用一些现成的 JavaScript 库,比如 i18next
。
- 引入 i18next 库:
在咱民宿的网页里,引入 i18next
库。
<script src="https://cdn.jsdelivr.net/npm/i18next@21.6.11/i18next.min.js"></script>
- 准备多语言资源文件:
准备好不同语言的翻译文件,比如 en.json
(英文)、zh.json
(中文)。
// en.json
{
"welcome": "Welcome to our homestay!",
"rooms": "Rooms",
"book": "Book Now"
}
// zh.json
{
"welcome": "欢迎来到我们的民宿!",
"rooms": "房间",
"book": "立即预订"
}
- 初始化 i18next:
在咱的 JavaScript 代码里,初始化 i18next
。
i18next
.init({
lng: 'zh',
debug: true,
resources: {
en: {
translation: {
"welcome": "Welcome to our homestay!",
"rooms": "Rooms",
"book": "Book Now"
}
},
zh: {
translation: {
"welcome": "欢迎来到我们的民宿!",
"rooms": "房间",
"book": "立即预订"
}
}
}
}, function(err, t) {
// 初始化完成,更新页面内容
updateContent();
});
function updateContent() {
document.getElementById('welcome').textContent = i18next.t('welcome');
document.getElementById('rooms').textContent = i18next.t('rooms');
document.getElementById('book').textContent = i18next.t('book');
}
这段代码做了这几件事:
- 初始化
i18next
,设置默认语言为中文。 - 加载英文和中文的翻译文件。
updateContent
函数:根据当前语言,更新页面上的文本内容。
- 切换语言:
提供一个语言切换的按钮,让用户可以自己选择语言。
<button onclick="changeLanguage('en')">English</button>
<button onclick="changeLanguage('zh')">中文</button>
<script>
function changeLanguage(lng) {
i18next.changeLanguage(lng, function(err, t) {
updateContent();
});
}
</script>
这段代码很简单,点击按钮,就会切换语言,并更新页面内容。
六、总结
用 Service Worker 搞 PWA,确实能给咱民宿带来不少好处。虽然实现起来有点复杂,但只要一步一步来,肯定能搞定。到时候,咱民宿的网站就能像 App 一样,没网也能用,还能支持多语言,肯定能吸引更多游客!