前言

百度百科PWA:PWA(Progressive Web App)是一种理念,使用多种技术来增强web app的功能,可以让网站的体验变得更好,能够模拟一些原生功能,比如通知推送。在移动端利用标准化框架,让网页应用呈现和原生应用相似的体验。

优点

*一个PWA应用首先是一个网页,可以通过Web技术编写出一个网页应用,随后添加上App Manifest和
Service Worker来实现PWA的安装和离线等功能*
解决了哪些问题?

  • 可以添加至主屏幕,陆主屏幕图标可以实现启动动画以及隐藏地址栏
  • 实现离线缓存功能,即使用户手机没有网络,依然可以使用-些离线功能
  • 实现了消息推送

它解决了。上述提到的问题,这些特性将使得Web应用渐进式接近原生App。

关于PWA大家可以百度或者打开这个详细了解,不过没什么用

效果图

PWA效果

网站开启PWA教程

  1. 开启Https-强制跳转——这个是基本必须
  2. 根目录上传sw.js,这个文件自己创建,内容看下面(注意要修改里面需要缓存的xhr请求!!)
  3. 根目录上传manifest.json并修改内容

name和short_name是标题‖description是描述‖src是icon图标

sw.js内容

点击展开

// sw.js
var apiCacheName = 'api-0-1-1';
self.addEventListener('fetch', function (e) {
    // 需要缓存的xhr请求
    var cacheRequestUrls = [
        './index.html',
        './main.css'
    ];
    console.log('现在正在请求:' + e.request.url);

    // 判断当前请求是否需要缓存
    var needCache = cacheRequestUrls.some(function (url) {
        return e.request.url.indexOf(url) > -1;
    });

    /**** 这里是对XHR数据缓存的相关操作 ****/
    if (needCache) {
        // 需要缓存
        // 使用fetch请求数据,并将请求结果clone一份缓存到cache
        // 此部分缓存后在browser中使用全局变量caches获取
        caches.open(apiCacheName).then(function (cache) {
            return fetch(e.request).then(function (response) {
                cache.put(e.request.url, response.clone());
                return response;
            });
        });
    }
    /* ******************************* */

    else {
        // 非api请求,直接查询cache
        // 如果有cache则直接返回,否则通过fetch请求
        e.respondWith(
            caches.match(e.request).then(function (cache) {
                return cache || fetch(e.request);
            }).catch(function (err) {
                console.log(err);
                return fetch(e.request);
            })
        );
    }
});

// sw.js
// 监听activate事件,激活后通过cache的key来判断是否更新cache中的静态资源
self.addEventListener('activate', function (e) {
    console.log('Service Worker 状态: activate');
    var cachePromise = caches.keys().then(function (keys) {
        return Promise.all(keys.map(function (key) {
            if (key !== cacheName) {
                return caches.delete(key);
            }
        }));
    })
    e.waitUntil(cachePromise);
    return self.clients.claim();
});

function getApiDataFromCache(url) {
    if ('caches' in window) {
        return caches.match(url).then(function (cache) {
            if (!cache) {
                return;
            }
            return cache.json();
        });
    }
    else {
        return Promise.resolve();
    }
}

function queryBook() {
    // ……
    // 远程请求
    var remotePromise = getApiDataRemote(url);
    var cacheData;
    // 首先使用缓存数据渲染
    getApiDataFromCache(url).then(function (data) {
        if (data) {
            loading(false);
            input.blur();            
            fillList(data.books);
            document.querySelector('#js-thanks').style = 'display: block';
        }
        cacheData = data || {};
        return remotePromise;
    }).then(function (data) {
        if (JSON.stringify(data) !== JSON.stringify(cacheData)) {
            loading(false);                
            input.blur();
            fillList(data.books);
            document.querySelector('#js-thanks').style = 'display: block';
        }
    });
    // ……
}

manifest.json内容

{
    "name": "不冷's Blog",
    "short_name": "不冷's Blog",
    "description": "迷失的人迷失了,相逢的人会再相逢",
    "icons": [
        {
            "src": "https://q1.qlogo.cn/g?b=qq&nk=2085886325&s=640",
            "sizes": "64x64",
            "type": "image/png"
        },
        {
            "src": "https://q1.qlogo.cn/g?b=qq&nk=2085886325&s=640",
            "sizes": "120x120",
            "type": "image/png"
        },
        {
            "src": "https://q1.qlogo.cn/g?b=qq&nk=2085886325&s=640",
            "sizes": "144x144",
            "type": "image/png"
        },
        {
            "src": "https://q1.qlogo.cn/g?b=qq&nk=2085886325&s=640",
            "sizes": "152x152",
            "type": "image/png"
        },
        {
            "src": "https://q1.qlogo.cn/g?b=qq&nk=2085886325&s=640",
            "sizes": "192x192",
            "type": "image/png"
        },
        {
            "src": "https://q1.qlogo.cn/g?b=qq&nk=2085886325&s=640",
            "sizes": "384x384",
            "type": "image/png"
        },
        {
            "src": "https://q1.qlogo.cn/g?b=qq&nk=2085886325&s=640",
            "sizes": "512x512",
            "type": "image/png"
        }
    ],
    "start_url": "/",
    "display": "standalone",
    "background_color": "#2196f3",
    "theme_color": "#2196f3",
    "lang": "en"
}

下一步

  1. 在主题header.php文件里插入

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

注意以下JS需写在<!DOCTYPE HTML>前面(我没写也实现了)

 <?php
if ($_SERVER['HTTP_X_REQUESTED_WITH'] == "XMLHttpRequest" && ($this->is('post')||$this->is('page')) && stripos($_SERVER['HTTP_REFERER'], $_SERVER['SERVER_NAME'])) {
   header('HTTP/1.1 200 OK');
   ini_set("display_errors", 1);
   $this->response($this->need('comments.php'));
   
}
?>
  1. 在主题footer.php文件里插入JS(handsome主题可以直接在后台外观中设置此处代码)
<script>
    if (navigator.serviceWorker) {
    navigator.serviceWorker.register('/service-worker.js')
        .then(function(registration) {
            console.log('service worker 注册成功');
        })
        .catch(function (err) {
    console.log('servcie worker 注册失败');
  });
}  
    </script>

总结

这东西真的挺复杂的!!!
参考文章:

  1. https://catni.cn/archives/17/
  2. http://www.hellojava.com/a/80352.html
  3. https://www.jianshu.com/p/fad8aa9e277f
  4. https://www.jianshu.com/p/25331bf16543
  5. https://segmentfault.com/a/1190000012353473
最后修改:2021 年 01 月 24 日 12 : 23 PM
如果觉得此文章有用,请随意打赏