HOOOS

咱这PWA民宿,没网也能看房订房!Service Worker 咋用?

0 4 乡村民宿老王 Service WorkerPWA离线应用
Apple

各位乡亲,我是老王,咱村口开了个民宿,这年头也得赶赶时髦,琢磨着怎么用点新技术,让大伙住得更舒坦。最近听说个叫 PWA 的玩意儿,说是能让手机像 App 一样用,还能离线用!这不,我就琢磨着,能不能用这 PWA 里的 Service Worker,把咱民宿搞得更洋气,让大伙儿没网也能看房订房?

一、啥是 Service Worker?能帮咱民宿干啥?

Service Worker,简单说,就像个在浏览器后台默默干活的“服务员”。它能拦截网络请求,缓存网页内容,还能在没网的时候,直接把缓存的内容拿出来用。这对于咱这种乡下民宿来说,简直是救星!

你想啊,来咱这儿玩的,不少都是城里人,手机信号不见得一直满格。有了 Service Worker,他们就能:

  • 离线浏览民宿介绍: 就算没网,也能看到咱民宿的照片、房型介绍、价格等等,心里有个数。
  • 离线预订房间: 没网也能填写预订信息,等有网了,自动提交,方便!
  • 离线查看用户评价: 看看住过的人怎么说,心里更有底。

二、Service Worker 咋实现离线民宿介绍?

这块儿是重点,我得好好琢磨琢磨。咱得先让 Service Worker 把民宿介绍相关的网页内容缓存起来。

  1. 注册 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 的代码。

  1. 编写 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 更新的时候,会执行这段代码,把旧的缓存清理掉。
  1. 测试离线访问:

把这些代码都放到咱民宿的网站上,然后用手机访问一下。第一次访问的时候,Service Worker 会把需要缓存的文件都下载下来。然后,断开手机的网络,再访问一次,看看是不是还能正常浏览民宿介绍?如果能,那就说明成功了!

三、Service Worker 咋实现离线预订房间和自动同步?

光能看还不够,还得能订!这块儿稍微复杂点,咱得用到一些技巧。

  1. 离线存储预订信息:

没网的时候,用户填写的预订信息,咱得先存在手机里。可以用 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 函数:获取所有未同步的预订信息。
  1. 监听网络状态:

一旦网络恢复,咱就得自动把离线存储的预订信息提交到服务器。

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 函数:获取所有未同步的预订信息,然后逐个发送到服务器。
  • 如果服务器返回成功,就删除本地存储的预订信息。
  1. 服务器端处理:

服务器端需要提供一个 /api/bookings 接口,用来接收客户端提交的预订信息,并保存到数据库里。

四、离线用户评价咋搞?

用户评价也挺重要,能让其他游客更了解咱民宿。这块儿跟离线预订房间类似,也需要用到离线存储和自动同步。

  1. 离线存储用户评价:

没网的时候,用户填写的评价信息,咱也得先存在手机里,可以用 IndexedDB

  1. 监听网络状态:

一旦网络恢复,咱就得自动把离线存储的评价信息提交到服务器。

  1. 服务器端处理:

服务器端需要提供一个 /api/reviews 接口,用来接收客户端提交的评价信息,并保存到数据库里。

五、多语言支持咋实现?

现在来咱这儿玩的,外国人也越来越多了,咱还得考虑多语言支持。这块儿可以用一些现成的 JavaScript 库,比如 i18next

  1. 引入 i18next 库:

在咱民宿的网页里,引入 i18next 库。

<script src="https://cdn.jsdelivr.net/npm/i18next@21.6.11/i18next.min.js"></script>
  1. 准备多语言资源文件:

准备好不同语言的翻译文件,比如 en.json(英文)、zh.json(中文)。

// en.json
{
  "welcome": "Welcome to our homestay!",
  "rooms": "Rooms",
  "book": "Book Now"
}

// zh.json
{
  "welcome": "欢迎来到我们的民宿!",
  "rooms": "房间",
  "book": "立即预订"
}
  1. 初始化 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 函数:根据当前语言,更新页面上的文本内容。
  1. 切换语言:

提供一个语言切换的按钮,让用户可以自己选择语言。

<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 一样,没网也能用,还能支持多语言,肯定能吸引更多游客!

点评评价

captcha
健康