PWA(Progressive web apps,渐进式 Web 应用)运用现代的 Web API 以及传统的渐进式增强策略来创建跨平台 Web 应用程序, 是Google 在2016年提出的概念,2017年落地的web技术。目的就是在移动端利用提供的标准化框架,在网页应用中实现和原生应用相近的用户体验的渐进式网页应用。
manifest是一个可配置的json文件,可以使web添加至桌面,设置启动图标,隐藏地址栏等操作
在html文件中引用配置文件
<link rel="manifest" href="manifest.json">
编写 manifest.json 文件
{
"name":"pwa渐进式web",
"short_name":"pwa",
"icons":[{
"src": "./image/icon.png",
"sizes": "144x144",
"type": "image/png"
}],
"background_color":"#9b59b6",
"theme_color":"#34495e",
"display":"standalone",
"start_url":"/index.html"
}
manifest 属性
属性明 | 描述 |
---|---|
name | 用于指定应用的名称和启动画面的文字 |
short_name | 应用的短名称,用于主屏显示 |
start_url | 指定应用启动加载的页面 |
icons | 指定各种环境中作为应用的图标,最佳144x144 |
background_color | 启动动画的背景颜色 |
theme_color | 应用程序的主题颜色 |
display | fullscreen:全屏显示,不显示状态栏;standalone:更像一个独立的应用程序;minimal-ui:拥有地址显示栏; |
浏览器中就已经可以看到配置信息了
install 注册成功时触发,主要用于缓存资源;
acvitate 激活时触发,主要用于删除旧资源;
fetch 发送请求时触发,主要用于操作缓存和读取网络资源;
if('serviceWorker' in navigator){};
;self.skipWaiting()
跳过等待,返回一个promise对象;event.waitUntil()
方法的扩展参数是一个promise对象,会在promise结束后结束当前生命周期函数,防止浏览器在异步操作;self.clients.claim()
立即获取控制权; // 页面加载完之后,注册serviceWorker
window.addEventListener('load',async ()=>{
// 检测是否可用
if('serviceWorker' in navigator){
try{
const registration = await navigator.serviceWorker.register('./sw.js');
console.log("注册成功",registration)
}catch(e){
console.log("注册失败",e)
}
}
});
sw.js 这三个写法基本固定
//注册
self.addEventListener('install', event => {
console.log('----install-----')
console.log(event)
//self.skipWaiting 会让service worker 跳过等待直接进入activate
//event.waitUntil 等待skipWaiting 结束后才进入activate
event.waitUntil(self.skipWaiting())
});
//激活
self.addEventListener('activate', event => {
console.log('----activate-----')
console.log(event)
//service worker 激活后,立即获取控制权
event.waitUntil(self.clients.claim());
});
//拦截请求
self.addEventListener('fetch',event => {
//可以抓取到所有网络请求
console.log('----fetch-----')
console.log( event)
});
刷新浏览器就可以看到控制台上相应生命周期输出的结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cgMbgCIe-1595210829835)(https://cdn.jsdelivr.net/gh/superliebe/picGo/20200718174427.png)]
类似于ajax,专门用于service worker 中请求数据使用 fetch(url,config)
fetch("/api/...").then(res=>{
//res得到的事响应式内容,是一个二进制流
//调用res.json 可以把数据转化为可读的json格式
return res.json()
}).then(data=>{
console.log(data)
})
通过推送告诉用户某信息,比如断网/联网的时候要通知到用户,提升用户体验。
Notification.permission 可以获取到当前用户通知 的权限
Notification.requestPremission() 可以请求用户授权。
new Notification(‘提示的标题’,{body:‘提示的内容’,icon:‘提示的图标’}) 可以显示通知。
//如果一进来我们发现用户没有联网就给用户一个通知
if(Notification.permission=='defalut'){
//授权开启通知
Notification.requestPermission();
}
if(!navigator.onLine){
//断网
console.log("断网")
new Notification("提示",{
body:'网络已断开,您访问的是缓存',icon:'/image/icon.png'})
}
window.addEventListener("online",()=>{
console.log("网络已连接")
new Notification("提示",{
body:'网络已连接,请刷新页面获取新的数据',icon:'/image/icon.png'})
})
配合service worker 来实现缓存
caches.api 常用方法
caches.open(cachesName).then(res=>{})
用户打开一个缓存,返回一个匹配cachesNam的catch对象promise,类似于链接数据库操作;caches.keys()
返回一个promise对象,包括所有缓存的key (数据库名) ;caches.delete(key)
根据key删除对应的缓存;cache 常用方法(单条数据操作)
cache.put(req,res)
把请求当key,并把对应的相应存储起来;cache.add(url)
根据url发起请求,并把相应结果存储起来;cache.addAll(url)
抓取一个url数组,并把结果都存起来;cache.match(req)
获取req对应的response;通过caches api 来实现读取离线缓存
html中引入对应的资源文件,在页面加载完之后,注册serviceWorker。
sw.js
//注册,主要缓存内容
const CACHE_NAME = 'cache_3'; //定义存储缓存的名字--类似数据库
const CACHE_URL = [
'/',
'/image/icon.png',
'/manifest.json',
'/index.css'
]
self.addEventListener('install', async event => {
//开启cache缓存,类似连接数据库
const cache = await caches.open(CACHE_NAME);
//cache 添加需要缓存的资源,使用await 等待把所有缓存存起来再进行
await cache.addAll(CACHE_URL)
//跳过等待直接进入activate
await self.skipWaiting();
});
//激活,主要清除缓存
self.addEventListener('activate', async event => {
//获取到左右资源的key
const keys = await caches.keys()
keys.forEach(key => {
if (key != CACHE_NAME) {
//旧资源
caches.delete(key)
}
})
//service worker 激活后,立即获取控制权
await self.clients.claim();
});
//监听请求,判断资源是否能够请求成功,成功则取相应结果,断网则取缓存内容
self.addEventListener('fetch', async event => {
//请求对象
const req = event.request;
//只缓存同源内容
const url = new URL(req.url);
if (url.origin !== location.origin) {
return
}
//给浏览器相应,
if (req.url.includes("/api")) {
//资源走网络优先
event.respondWith(networkFirst(req))
} else {
//资源走缓存优先
event.respondWith(cacheFrist(req))
}
});
//网络优先
async function networkFirst(req) {
//取缓存中读取
const cache = await caches.open(CACHE_NAME);
//先从网络获取资源
try {
const fresh = await fetch(req);
//获取到的数据应该再次更新到缓存当中,把响应的备份存到缓存当中
cache.put(req,fresh.clone())
return fresh
} catch (e) {
//匹配与req对应的资源
const cached = await cache.match(req);
return cached
}
}
//缓存优先
async function cacheFrist(req) {
//打开缓存
const cache = await caches.open(CACHE_NAME);
//取出对应数据
const cached = await cache.match(req)
if (cached) {
//如果从缓存中得到了,直接返回缓存
return cached
} else {
const fresh = await fetch(req);
return fresh
}
}
打开控制台,application中即可看到被缓存的文件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4uP2Wnic-1595210829839)(https://s1.ax1x.com/2020/07/18/U2C9H0.png)]
勾选network中的 offline online来关闭网络, 刷新页面会发现,即使断网的情况洗也可以访问到正常的数据。