PWA


PWA

这篇总结主要介绍一下PWA

介绍

1.是什么?是渐进式web应用,Progressive Web App,简称PWA。
2.PWA并不是靠特指某一项技术,而是经过应用一些新技术进行改进

是一个标准的PWA程序,必须包含3个部分。
一:https协议或者http://localhost,
二:manifest.json,
三:service worker

优势

渐进式-适用于所有浏览器
流程-借助Service Worker在离线或网络较差时能够正常访问
可安装-用户可以添加常用webapp到桌面
原生体验-和app一样,用于首屏加载动画,隐藏地址栏等体验
粘性-通过推送离线通知,让用户回流

核心技术

1.web app manifest : 应用程序清单

它是PWA技术集合的一部分,他的主要作用是让网站能够直接安装到设备的主屏幕上,无需下载
具体他就是一个JSON文件,在JSON文件去添加一些配置,添加完这些配置,就能将网站添加在桌面上。
优势:传统web app 入口需要网址/书签/收藏/直接搜索,才能去访问他的网址,同时粘性不高,用了一次不再使用

可以添加到页面,有唯一的图标和名称
有启动时间,避免生硬的过渡
隐藏浏览器相关的UI,比如地址栏

如何使用manifest

1.在项目根目录下创建一个manifest.json文件

2.在index.html中引入manifest.json文件

<link rel="manifest" href="manifest.json"/>

3.在manifest文件中提供常见的配置

{
    "name":"Hello PWA",
    "short_name":"PWA",
    "start_url":"",
    "icons":[
        {
            "src":" ",
            "sizes":"144*144",
            "type":"image/png"}],
    "background-color":"blue",
    "tieme_color":"pink",
    "display":"standalone"
}

name:用于指定应用的名称,用户安装横幅提示的名称和启动画面中的汉字
short_name:应用的短名称,用于主屏幕显示
start_url:指定用户从设备启动应用程序所加载的url,
就是你加载哪个页面为首次加载页面,可以是绝对路径与相对路径
icons:用于指定可在各种环境中作用应用程序图标的图像对应数组 144*144
background-color:用户指定启动动画的背景颜色
theme_color:用于指定应用程序的主题颜色,就是顶部背景颜色
display:用于指定web app显示模式
fullscreen:全屏显示
standalone:让应用看起来像一个独立的应用程序,包括不同的窗口,
在应用程序启动器中,拥有自己的图标
minimal:让应用看起来像一个独立的应用程序,但会有浏览地址栏

4.只支持https协议或者http://localhost下访问项目

2.service worker:持久的离线缓存

  1. 是一个标准的PWA程序,必须包含3个部分。
    一:https协议或者http://localhost,
    二:manifest.json,三:service worker
  2. service worker允许web应用在网络情况较差或者离线的情况下依旧可以访问
  3. service worker可以极大的提升web app的用户体验
  4. service worker是一个独立的worker线程,独立于当前网页进程,是一种特殊的web worker

web worker介绍

浏览器中的js是单线程的,同一时间只能做一件事,随着业务的增加,会造成严重的性能问题,
因此W3C提出了 web worker,他是脱离主线程之外的,将一些复杂耗时的活交给他,
完成通过后通过postMessage方法告诉主线程,web worker是一个独立的运行环境,不能操作DOM和BOM

web worker的使用

1.创建web worker

const worker = new Worker('work.js')

2.在web worker中进行复杂的计算

3.web worker计算结束后,通过self.postMessage(msg)给主线程发消息

4.主线程通过worker.onmessage = function(msg){}监听消息

5.主线程也可以通过用同样的方式来给web worker进行通讯

示例:

//在a.js文件夹中
console.log('start')
/*let sum = 0
for(let i = 0;i < 100000000;i++) {
    sum+=i
}*/
//1.创建worker实例
const worker = new Worker('work.js')
//2.拿到web worker传过来的消息,监听message事件
worker.addEventListener('message',e=>{
    console.log(e.data)  //e.data就是work.js给我们发送的消息
})

console.log('end')
//在work.js文件夹中操作大量运算数据代码,web worker是一个独立的运行环境,不能操作DOM和BOM
//1.运算复杂数据
let sum = 0
for(let i = 0;i < 100000000;i++) {
    sum+=i
}
//2.发消息给主线程
self.postMessage({sum:sum})

service worker介绍

web worker是临时的,每次做的事情无法持久存储下来

而service worker则是不一样的,一旦被创建(install),就会永远存在,
除非手动删除(unregister),且用到时可以直接唤醒,不用的时候自动睡眠。

同时它还可以通过代码拦截请求与响应,缓存文件(他会决定你是读缓存还是读取服务器,
并且能够将读取服务器的数据缓存一份在CacheStorage中),因此你网页离线了,就会读取缓存。

离线内容也能操作,就是你要缓存哪些,不缓存哪些

必须在https环境下才能工作

异步实现,内部大部分都是通过promise实现

service worker的使用

1.在window.onload中注册service worker,防止与其他资源竞争,
即在网页加载完成以后再去注册sevice worker
2.navigator对象内置了serviceWorker属性
3.service worker在老版本的浏览器不支持,需要兼容

if('serviceWorker' in navigator) {}

4.注册service worker :**navigator.serviceWorker.register(‘./sw.js’)**,返回一个promise对象

//1.在网页加载完成以后再去注册sevice worker
window.addEventListener('load',()=>{
    //2.检测是否兼容
    if('serviceWorker' in navigator) {
        //3.调用方法,并且创建sw.js文件
        navigator.serviceWorker.register('./sw.js')
        .then(res=>console.log(res))
        .catch(err=>{console.log(err)})
    }
}

5.操作sw.js文件

service worker生命周期事件

1.install事件会在service worker注册成功时触发,主要用于缓存
2.activate事件会在service worker激活时触发,主要用于删除旧的资源
3.fetch事件会在发送请求的时候触发,主要操作缓存或者读取网络资源

注意:
1.如果sw.js文件发生了改变,install事件会被重新触发,其余的时候都不会再触发
2.activate事件会在install事件后触发,但如果发现已经存在service worker,
那么就处于等待状态,直到当前的service worker终止,才会再次调用
3.可以通过**self.skipWaiting()方法跳过等待,返回一个promise对象
4.可以通过
event.waitUntil()方法扩的参数是一个promise对象,
会在promise结束后才会结束当前生命周期函数,防止浏览器在异步操作之前就停止了生命周期
5.service worker激活后,会在下一次刷新页面的时候才会生效,
可以通过
self.clients.claim()**立即获取控制权

//self 关键字表示当前的 Service Worker 实例
self.addEventListenter('install',e=>{
    console.log(e)
    //让service worker跳过等待,直接进入activate
    //让skipWaiting这个异步结束以后,才进入activate
    event.waitUntil(self.skipWaiting())
})
self.addEventListenter('activate',e=>{
    console.log(e)
    //表示service worker激活后,立即获取控制权
    //让self.clients.claim()这个异步结束以后,才进入fetch
    event.waitUntil(self.clients.claim())
})
self.addEventListenter('fetch',e=>{
    console.log(e)
})

fetch api

1.它是js提供的一个网络请求接口,用于访问与操作http管道部分,
例如请求与响应,他是基于promise实现的
2.fetch(url,config)用于发送http请求,返回一个包含结果的promise
3.response(返回的数据)是二进制数据流,需要调用json()方法转换成json数据
4.config常见参数:

  1. body:用于设置请求体
  2. headers:请求头
  3. method:请求方式
//由于window对象上有fetch属性
fetch('请求路径').then(res=>{
    //res请求得到的响应内容是二进制的流
    //调用res.json()方法,可以把数据变成json格式
    //它返回的是一个promise
    return res.json()
}).then(data=>{
    //data则是你需要的数据
    console.log(data)
})

cache storage

1.cacheStorage接口表示Cache对象的存储。配合service worker来实现资源的缓存

2.caches api类似于数据库的操作:
**caches.open(cacheName).then(function(cache){这里拿到cache对象})**:
用于打开缓存,返回一个匹配cacheName的cache对象的promise,类似于连接数据库

caches.keys():返回一个promise对象,包括所有的缓存的key(数据库名)

caches.delete(key):根据key,删除对应缓存

3.cache对象常用方法

cache接口为缓存的request/response对象对提供存储机制

cache put(req,res):把请求当作key,并且对应的响应存储起来

cache add(url) :根据url发送请求,并且把响应存储起来

cache addAll(urls):抓取url数组,并且把他们存储起来

catch math(req):获取req对应的response

完整版

某个js文件

//1.在网页加载完成以后再去注册sevice worker
window.addEventListener('load',async ()=>{
    //2.检测是否兼容
    if('serviceWorker' in navigator) {
        //3.调用方法,并且创建sw.js文件
        try{
            const registration = navigator.serviceWorker.register('./sw.js')
        }catch(e){
            console.log("注册失败")
        }
    }
}
//页面一进来,看用户是否有网络,没有则给用户一个通知
if(Notification .permission === 'default') {
    Notification.requestPremission()
}
if(!navigator.onLine) {
    new Notification('提示',{body:'你当前没有网络,你访问的是缓存'})
}
//如果有网络
window.addEventListener('online',()=>{
   new Notification('提示',{body:'你已连上网络,你访问的是最新数据'})
})

sw.js文件

//self 关键字表示当前的 Service Worker 实例
//主要缓存内容
const CACHE_NAME = "cache_v1"
self.addEventListenter('install',async e=>{
    //#1 开启一个cache,得到一个cache对象
    cosnt cache = await caches.open(CACHE_NAME)
    //#2 拿到cache对象之后,调用addAll(),将数据存储起来
    //等待cache把所有资源存起来
    await cache.addAll([
        '/',   // '/index.html'主页,只需要写一个/即可
        '/images/logo.png',
        '/mainfest.json',
        '/index.css'
    ])
    
    await self.skipWaiting()
    
    //让service worker跳过等待,直接进入activate
    //让skipWaiting这个异步结束以后,才进入activate
    //event.waitUntil(self.skipWaiting())
})

//主要清除旧的资源
self.addEventListenter('activate',async e=>{
    //#1 获取所有资源的key
    cosnt keys = await caches.keys()
    keys.forEach(key=>{
        if(keys!==CACHE_NAME) {
        caches.delete(key)
      }
    })
    
    await self.clients.claim()
    
    //表示service worker激活后,立即获取控制权
    //让self.clients.claim()这个异步结束以后,才进入fetch
    //event.waitUntil(self.clients.claim())
})

//在请求发送时触发
//判断资源是否能够请求成功,如果能够请求成功,
//就响应成功的结果,如果请求失败了,则去读取缓存
self.addEventListenter('fetch',e=>{
    //请求对象
    const req = event.request
    //给浏览器响应
    event.respondWith(fn1(req))
})
//网络优先
async function fn1(req) {
    try{
        //成功,则网络读取资源
       cosnt fresh = await fetch(req)
        return fresh
    }catch(e){
        //失败则去读缓存
        const cache = await caches.open(CACHE_NAME)
        //缓存的内容
        const cached = await cache.match(req)
        return cached
    }
}
// 缓存优先

Notification api

Notification api的通知接口用于向用户配置和显示桌面通知

Notification .permission可以获取当前用户的授权情况
Default:默认的,未授权
Denied:拒绝的。如果拒绝,则无法再次请求授权,也无法获取弹框提醒
Granted:授权的,可以弹窗提醒

通过Notification.requestPremission()可以请求用户授权

通过new Notification(‘title’,{body:’ ‘,icon:’ ‘})可以显示通知

在授权通过的情况下,可以在service worker中显示通知
self.registration.showNotification({‘你好’,{body:’msg})

如何在vue cli 配置,打包出来的 public,自动引入某个文件?

const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
  configureWebpack: {
    plugins: [
      new CopyWebpackPlugin({
        patterns: [
          {
            from: 'path/to/your/file',
            to: 'path/in/public/directory',
            toType: 'dir',
          },
        ],
      }),
    ],
  },
};

path/to/your/file 替换为要自动复制到public目录的文件路径,
path/in/public/directory 替换为在public目录中要存储文件的路径。

注意:CopyWebpackPlugin 是一个Webpack插件


文章作者: 冷杨威
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 冷杨威 !
 上一篇
Vue3 Vue3
Vue3本篇主要总结了vue3的知识与概念
2023-07-20
下一篇 
Pinia Pinia
Pinia在Vue3的使用本篇文章主要是总结Pinia在Vue3的使用
2023-07-20
  目录
-->