今天给我的项目搞了个PWA应用,网上的Service worker的资料非常复杂,如果你只是想要做一个简单的PWA应用,这篇文章是你最好的选择。
准备
你不需要vue,不需要npm!
你只需要一个代码编辑器,一个正常的浏览器(禁止使用IE😕),最好有一个Live server或者一个python(正常的版本)做服务器就够了!
开始
我相信你有一个index.html,一个js,对吧(如果没有,请去看别的文章)
注意:你的项目最好是静态的,不然会有一些困难
首先建一个minifest.json
文件(名字不要错,不然浏览器的警告你受不了)
在index.html
的<head>
里写上
<link rel="manifest" href="manifest.json">
在minifest.json
中
{
"name": "名字",
"short_name": "名字",
"display": "standalone",
"start_url": "/win12/index.html",
"background_color": "#000",//加载时的背景(默认#fff)
"icons": [
{
"src": "logo.png",//自己准备
"sizes": "144x144",
"type": "image/png"
}
]
}
以上这些都不重要,重要的在下面:
打开你的js文件,在末尾加上
navigator.serviceWorker.register('sw.js',{scope:'./'});
这是在将sw.js注册为一个serviceWorker,scope是它的作用域,这意味着如果sw.js在/win12/sw.js
,那么作用域就不能是/
或/win13
。
当然这样写会更 高端 全面
if('serviceWorker' in navigator){
navigator.serviceWorker.register('sw.js',{scope:'./'});
}
当然,如果你现在还没有创建一个sw.js,就把它创建一下吧
基本功能
serviceWorker相当于一个海关,它可以审页面发出的所有请求,比如说页面请求style.css
,sw就可以截下这个请求,然后给页面甩回去一个 404 别的响应
这个看起来很鸡肋,但是这还不是他的主要功能
它可以干什么呢?
它可以吧服务器的东西全部存到电脑上,等页面发出请求,就直接把电脑上的资源返回去
怎么样?高不高级?这就意味着,页面可以离线访问!
当然,如果你的项目不是静态,就只能将css、图片等存一下
怎么实现呢?很简单:
// sw.js
this.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request).then(res => {
return res ||
fetch(event.request)
.then(responese => {
const responeseClone = responese.clone();
caches.open(version).then(cache => {
cache.put(event.request, responeseClone);
})
return responese;
});
})
)
});
很好理解,页面发请求电脑上有就直接返回,没有就找服务器
return res || //有就直接返回
fetch(event.request)
.then(responese => {
const responeseClone = responese.clone();
caches.open(version).then(cache => {
// ~~~~~~~
//这里的version是版本号,具体后面会讲
cache.put(event.request, responeseClone);
});//没有就请求服务器然后再存在电脑上
return responese;
});
不需要详细理解
当然如果是动态,就要有选择性地存,不能把动态的页面也存了
// sw.js this.addEventListener('install', function (event) { event.waitUntil( caches.open(version).then(function (cache) { return cache.addAll([ './style.css', './script.js' //自己一个一个写吧,加油! ]); }) ); });
打开Live server或者python server(python -m http.server 8000
)
这时候就要来看看浏览器怎么处置我们的sw了
在devtool的"应用程序"标签中(没有的点加号添加)的缓存存储中可以看到咱们sw存的东西了
如果你什么都没有看见----
点开
清单
标签,看看警告吧
这时候看到的v3.0.0
是之前的version
,
这里就要谈一谈sw的更新机制了
更新
sw.js
是不会把自己存在缓存里的,所以离线状态下管理缓存的是浏览器,当然这个就不是我们要管的了
缓存是一"组"一"组"的,比如v3.0.0
就是这个组的名称,所以给项目的更新加上一个版本号是必须的,sw需要根据版本号判断是否需要更新。
这就意味着你如果在服务器上更改了内容,但没有改版本号,用户访问的网站将不会有任何更改。
更新电脑中的缓存很简单,只需要在sw.js
中加上
let cacheNames = [version];
this.addEventListener('activate', function (event) {
event.waitUntil(
caches.keys().then(keys => {
return Promise.all[keys.map(key => {
if (!cacheNames.includes(key)) {
return caches.delete(key);
}
})]
})
);
});
事件activate
会在pwa启动时触发
只要与当前版本不符,就删掉
很简单吧
这时sw.js
大概长这样
let version='v3.0.0';
this.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request).then(res => {
return res ||
fetch(event.request)
.then(responese => {
const responeseClone = responese.clone();
caches.open(version).then(cache => {
cache.put(event.request, responeseClone);
})
return responese;
});
})
)
});
let cacheNames = [version];
this.addEventListener('activate', function (event) {
event.waitUntil(
caches.keys().then(keys => {
return Promise.all[keys.map(key => {
if (!cacheNames.includes(key)) {
return caches.delete(key);
}
})]
})
);
});
测试
相信你的代码已经很完善了,接下来开始测试吧
打开你的网站,你应该看到这个
你可以试着断开网络,更改版本号,相信你的pwa可以正常地运行了!
通信
注意:
sw.js
不能控制html元素,如果你想这样------看看下面
如果你需要在页面显示更新信息什么的,你就需要在页面与sw.js
之间通信
页面->sw.js
页面 :
navigator.serviceWorker.controller.postMessage(
"你好吗,sw.js?"
);
sw.js
接收 :
this.addEventListener('message', function (event) {
console.log(event.data);
});
很简单
sw.js
->页面
在接收信息之后,要想回复,就这样
this.addEventListener('message', function (event) {
event.source.postMessage('我很好');
});
页面接收
navigator.serviceWorker.addEventListener('message', function (e) {
console.log(e.data);
});
当然,如果sw.js
想要主动一点,也可以
this.clients.matchAll().then(client => {
client[0].postMessage('不用问了,我很好');
})
注意了,因为
sw.js
独立于页面之外,如果在刷新时触发,信息会发到刷新前的页面
如果是在 启动/更新 时发送,页面还没有加载出来,所以this.clients
会为空
所以这种情况可能需要加一个setTimeout
或者等页面加载出来并发信息给sw.js
后再回复
总结
高级吗?简单吗?
最后大家可以看一看这个示例 : Windows12 网页版