当前位置:千赢国际官网 > 千赢网页手机版登入 > 前端的数据库,入门教程

前端的数据库,入门教程

文章作者:千赢网页手机版登入 上传时间:2019-10-05

前端的数据库:IndexedDB入门

2014/12/27 · 未分类 · IndexedDB

本文由 伯乐在线 - cucr 翻译,黄利民 校稿。未经许可,禁止转载!
英文出处:www.codemag.com。欢迎加入翻译组。

应用程序需要数据。对大多数Web应用程序来说,数据在服务器端组织和管理,客户端通过网络请求获取。随着浏览器变得越来越有能力,因此可选择在浏览器存储和操纵应用程序数据。

本文向你介绍名为IndexedDB的浏览器端文档数据库。使用lndexedDB,你可以通过惯于在服务器端数据库几乎相同的方式创建、读取、更新和删除大量的记录。请使用本文中可工作的代码版本去体验,完整的源代码可以通过GitHub库找到。

读到本教程的结尾时,你将熟悉IndexedDB的基本概念以及如何实现一个使用IndexedDB执行完整的CRUD操作的模块化JavaScript应用程序。让我们稍微亲近IndexedDB并开始吧。

什么是IndexedDB

一般来说,有两种不同类型的数据库:关系型和文档型(也称为NoSQL或对象)。关系数据库如SQL Server,MySQL,Oracle的数据存储在表中。文档数据库如MongoDB,CouchDB,Redis将数据集作为个体对象存储。IndexedDB是一个文档数据库,它在完全内置于浏览器中的一个沙盒环境中(强制依照(浏览器)同源策略)。图1显示了IndexedDB的数据,展示了数据库的结构

图片 1

图1:开发者工具查看一个object store

全部的IndexedDB API请参考完整文档

渐进式Web应用(PWA)入门教程(下)

2018/05/25 · 基础技术 · PWA

原文出处: Craig Buckler   译文出处:葡萄城控件   

上篇文章我们对渐进式Web应用(PWA)做了一些基本的介绍。

渐进式Web应用(PWA)入门教程(上)

在这一节中,我们将介绍PWA的原理是什么,它是如何开始工作的。

HTML5实现屏幕手势解锁

2015/07/18 · HTML5 · 1 评论 · 手势解锁

原文出处: AlloyTeam   

效果展示

图片 2

实现原理 利用HTML5的canvas,将解锁的圈圈划出,利用touch事件解锁这些圈圈,直接看代码。

JavaScript

function createCircle() {// 创建解锁点的坐标,根据canvas的大小来平均分配半径 var n = chooseType;// 画出n*n的矩阵 lastPoint = []; arr = []; restPoint = []; r = ctx.canvas.width / (2 4 * n);// 公式计算 半径和canvas的大小有关 for (var i = 0 ; i < n ; i ) { for (var j = 0 ; j < n ; j ) { arr.push({ x: j * 4 * r 3 * r, y: i * 4 * r 3 * r }); restPoint.push({ x: j * 4 * r 3 * r, y: i * 4 * r 3 * r }); } } //return arr; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function createCircle() {// 创建解锁点的坐标,根据canvas的大小来平均分配半径
 
        var n = chooseType;// 画出n*n的矩阵
        lastPoint = [];
        arr = [];
        restPoint = [];
        r = ctx.canvas.width / (2 4 * n);// 公式计算 半径和canvas的大小有关
        for (var i = 0 ; i < n ; i ) {
            for (var j = 0 ; j < n ; j ) {
                arr.push({
                    x: j * 4 * r 3 * r,
                    y: i * 4 * r 3 * r
                });
                restPoint.push({
                    x: j * 4 * r 3 * r,
                    y: i * 4 * r 3 * r
                });
            }
        }
        //return arr;
    }

canvas里的圆圈画好之后可以进行事件绑定

JavaScript

function bindEvent() { can.addEventListener("touchstart", function (e) { var po = getPosition(e); console.log(po); for (var i = 0 ; i < arr.length ; i ) { if (Math.abs(po.x - arr[i].x) < r && Math.abs(po.y - arr[i].y) < r) { // 用来判断起始点是否在圈圈内部 touchFlag = true; drawPoint(arr[i].x,arr[i].y); lastPoint.push(arr[i]); restPoint.splice(i,1); break; } } }, false); can.addEventListener("touchmove", function (e) { if (touchFlag) { update(getPosition(e)); } }, false); can.addEventListener("touchend", function (e) { if (touchFlag) { touchFlag = false; storePass(lastPoint); setTimeout(function(){ init(); }, 300); } }, false); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function bindEvent() {
        can.addEventListener("touchstart", function (e) {
             var po = getPosition(e);
             console.log(po);
             for (var i = 0 ; i < arr.length ; i ) {
                if (Math.abs(po.x - arr[i].x) < r && Math.abs(po.y - arr[i].y) < r) { // 用来判断起始点是否在圈圈内部
 
                    touchFlag = true;
                    drawPoint(arr[i].x,arr[i].y);
                    lastPoint.push(arr[i]);
                    restPoint.splice(i,1);
                    break;
                }
             }
         }, false);
         can.addEventListener("touchmove", function (e) {
            if (touchFlag) {
                update(getPosition(e));
            }
         }, false);
         can.addEventListener("touchend", function (e) {
             if (touchFlag) {
                 touchFlag = false;
                 storePass(lastPoint);
                 setTimeout(function(){
 
                    init();
                }, 300);
             }
 
         }, false);
    }

接着到了最关键的步骤绘制解锁路径逻辑,通过touchmove事件的不断触发,调用canvas的moveTo方法和lineTo方法来画出折现,同时判断是否达到我们所画的圈圈里面,其中lastPoint保存正确的圈圈路径,restPoint保存全部圈圈去除正确路径之后剩余的。 Update方法:

JavaScript

function update(po) {// 核心变换方法在touchmove时候调用 ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); for (var i = 0 ; i < arr.length ; i ) { // 每帧先把面板画出来 drawCle(arr[i].x, arr[i].y); } drawPoint(lastPoint);// 每帧花轨迹 drawLine(po , lastPoint);// 每帧画圆心 for (var i = 0 ; i < restPoint.length ; i ) { if (Math.abs(po.x - restPoint[i].x) < r && Math.abs(po.y - restPoint[i].y) < r) { drawPoint(restPoint[i].x, restPoint[i].y); lastPoint.push(restPoint[i]); restPoint.splice(i, 1); break; } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function update(po) {// 核心变换方法在touchmove时候调用
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
 
        for (var i = 0 ; i < arr.length ; i ) { // 每帧先把面板画出来
            drawCle(arr[i].x, arr[i].y);
        }
 
        drawPoint(lastPoint);// 每帧花轨迹
        drawLine(po , lastPoint);// 每帧画圆心
 
        for (var i = 0 ; i < restPoint.length ; i ) {
            if (Math.abs(po.x - restPoint[i].x) < r && Math.abs(po.y - restPoint[i].y) < r) {
                drawPoint(restPoint[i].x, restPoint[i].y);
                lastPoint.push(restPoint[i]);
                restPoint.splice(i, 1);
                break;
            }
        }
 
    }

最后就是收尾工作,把路径里面的lastPoint保存的数组变成密码存在localstorage里面,之后就用来处理解锁验证逻辑了

JavaScript

function storePass(psw) {// touchend结束之后对密码和状态的处理 if (pswObj.step == 1) { if (checkPass(pswObj.fpassword, psw)) { pswObj.step = 2; pswObj.spassword = psw; document.getElementById('title').innerHTML = '密码保存成功'; drawStatusPoint('#2CFF26'); window.localStorage.setItem('passwordx', JSON.stringify(pswObj.spassword)); window.localStorage.setItem('chooseType', chooseType); } else { document.getElementById('title').innerHTML = '两次不一致,重新输入'; drawStatusPoint('red'); delete pswObj.step; } } else if (pswObj.step == 2) { if (checkPass(pswObj.spassword, psw)) { document.getElementById('title').innerHTML = '解锁成功'; drawStatusPoint('#2CFF26'); } else { drawStatusPoint('red'); document.getElementById('title').innerHTML = '解锁失败'; } } else { pswObj.step = 1; pswObj.fpassword = psw; document.getElementById('title').innerHTML = '再次输入'; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function storePass(psw) {// touchend结束之后对密码和状态的处理
        if (pswObj.step == 1) {
            if (checkPass(pswObj.fpassword, psw)) {
                pswObj.step = 2;
                pswObj.spassword = psw;
                document.getElementById('title').innerHTML = '密码保存成功';
                drawStatusPoint('#2CFF26');
                window.localStorage.setItem('passwordx', JSON.stringify(pswObj.spassword));
                window.localStorage.setItem('chooseType', chooseType);
            } else {
                document.getElementById('title').innerHTML = '两次不一致,重新输入';
                drawStatusPoint('red');
                delete pswObj.step;
            }
        } else if (pswObj.step == 2) {
            if (checkPass(pswObj.spassword, psw)) {
                document.getElementById('title').innerHTML = '解锁成功';
                drawStatusPoint('#2CFF26');
            } else {
                drawStatusPoint('red');
                document.getElementById('title').innerHTML = '解锁失败';
            }
        } else {
            pswObj.step = 1;
            pswObj.fpassword = psw;
            document.getElementById('title').innerHTML = '再次输入';
        }
 
    }

解锁组件

将这个HTML5解锁写成了一个组件,放在

二维码体验: 图片 3

 

参考资料:

1 赞 4 收藏 1 评论

图片 4

设计典范

IndexedDB的架构很像在一些流行的服务器端NOSQL数据库实现中的设计典范类型。面向对象数据通过object stores(对象仓库)进行持久化,所有操作基于请求同时在事务范围内执行。事件生命周期使你能够控制数据库的配置,错误通过错误冒泡来使用API管理。

第一步:使用HTTPS

渐进式Web应用程序需要使用HTTPS连接。虽然使用HTTPS会让您服务器的开销变多,但使用HTTPS可以让您的网站变得更安全,HTTPS网站在Google上的排名也会更靠前。

由于Chrome浏览器会默认将localhost以及127.x.x.x地址视为测试地址,所以在本示例中您并不需要开启HTTPS。另外,出于调试目的,您可以在启动Chrome浏览器的时候使用以下参数来关闭其对网站HTTPS的检查:

  • –user-data-dir
  • –unsafety-treat-insecure-origin-as-secure

对象仓库

object store是IndexedDB数据库的基础。如果你使用过关系数据库,通常可以将object store等价于一个数据库表。Object stores包括一个或多个索引,在store中按照一对键/值操作,这提供一种快速定位数据的方法。

当你配置一个object store,你必须为store选择一个键。键在store中可以以“in-line”或“out-of-line”的方式存在。in-line键通过在数据对象上引用path来保障它在object store的唯一性。为了说明这一点,想想一个包括电子邮件地址属性Person对象。您可以配置你的store使用in-line键emailAddress,它能保证store(持久化对象中的数据)的唯一性。另外,out-of-line键通过独立于数据的值识别唯一性。在这种情况下,你可以把out-of-line键比作一个整数值,它(整数值)在关系数据库中充当记录的主键。

图1显示了任务数据保存在任务的object store,它使用in-line键。在这个案例中,键对应于对象的ID值。

第二步:创建一个应用程序清单(Manifest)

应用程序清单提供了和当前渐进式Web应用的相关信息,如:

  • 应用程序名
  • 描述
  • 所有图片(包括主屏幕图标,启动屏幕页面和用的图片或者网页上用的图片)

本质上讲,程序清单是页面上用到的图标和主题等资源的元数据。

程序清单是一个位于您应用根目录的JSON文件。该JSON文件返回时必须添加Content-Type: application/manifest json 或者 Content-Type: application/jsonHTTP头信息。程序清单的文件名不限,在本文的示例代码中为manifest.json

{ "name" : "PWA Website", "short_name" : "PWA", "description" : "An example PWA website", "start_url" : "/", "display" : "standalone", "orientation" : "any", "background_color" : "#ACE", "theme_color" : "#ACE", "icons": [ { "src" : "/images/logo/logo072.png", "sizes" : "72x72", "type" : "image/png" }, { "src" : "/images/logo/logo152.png", "sizes" : "152x152", "type" : "image/png" }, { "src" : "/images/logo/logo192.png", "sizes" : "192x192", "type" : "image/png" }, { "src" : "/images/logo/logo256.png", "sizes" : "256x256", "type" : "image/png" }, { "src" : "/images/logo/logo512.png", "sizes" : "512x512", "type" : "image/png" } ] }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
  "name"              : "PWA Website",
  "short_name"        : "PWA",
  "description"       : "An example PWA website",
  "start_url"         : "/",
  "display"           : "standalone",
  "orientation"       : "any",
  "background_color"  : "#ACE",
  "theme_color"       : "#ACE",
  "icons": [
    {
      "src"           : "/images/logo/logo072.png",
      "sizes"         : "72x72",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo152.png",
      "sizes"         : "152x152",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo192.png",
      "sizes"         : "192x192",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo256.png",
      "sizes"         : "256x256",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo512.png",
      "sizes"         : "512x512",
      "type"          : "image/png"
    }
  ]
}

程序清单文件建立完之后,你需要在每个页面上引用该文件:

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

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

以下属性在程序清单中经常使用,介绍说明如下:

  • name: 用户看到的应用名称
  • short_name: 应用短名称。当显示应用名称的地方不够时,将使用该名称。
  • description: 应用描述。
  • start_url: 应用起始路径,相对路径,默认为/。
  • scope: URL范围。比如:如果您将“/app/”设置为URL范围时,这个应用就会一直在这个目录中。
  • background_color: 欢迎页面的背景颜色和浏览器的背景颜色(可选)
  • theme_color: 应用的主题颜色,一般都会和背景颜色一样。这个设置决定了应用如何显示。
  • orientation: 优先旋转方向,可选的值有:any, natural, landscape, landscape-primary, landscape-secondary, portrait, portrait-primary, and portrait-secondary
  • display: 显示方式——fullscreen(无Chrome),standalone(和原生应用一样),minimal-ui(最小的一套UI控件集)或者browser(最古老的使用浏览器标签显示)
  • icons: 一个包含所有图片的数组。该数组中每个元素包含了图片的URL,大小和类型。

基于事务

不同于一些传统的关系数据库的实现,每一个对数据库操作是在一个事务的上下文中执行的。事务范围一次影响一个或多个object stores,你通过传入一个object store名字的数组到创建事务范围的函数来定义。

创建事务的第二个参数是事务模式。当请求一个事务时,必须决定是按照只读还是读写模式请求访问。事务是资源密集型的,所以如果你不需要更改data store中的数据,你只需要以只读模式对object stores集合进行请求访问。

清单2演示了如何使用适当的模式创建一个事务,并在这片文章的 Implementing Database-Specific Code 部分进行了详细讨论。

第三步:创建一个 Service Worker

Service Worker 是一个可编程的服务器代理,它可以拦截或者响应网络请求。Service Worker 是位于应用程序根目录的一个个的JavaScript文件。

您需要在页面对应的JavaScript文件中注册该ServiceWorker:

if ('serviceWorker' in navigator) { // register service worker navigator.serviceWorker.register('/service-worker.js'); }

1
2
3
4
if ('serviceWorker' in navigator) {
  // register service worker
  navigator.serviceWorker.register('/service-worker.js');
}

如果您不需要离线的相关功能,您可以只创建一个 /service-worker.js文件,这样用户就可以直接安装您的Web应用了!

Service Worker这个概念可能比较难懂,它其实是一个工作在其他线程中的标准的Worker,它不可以访问页面上的DOM元素,没有页面上的API,但是可以拦截所有页面上的网络请求,包括页面导航,请求资源,Ajax请求。

上面就是使用全站HTTPS的主要原因了。假设您没有在您的网站中使用HTTPS,一个第三方的脚本就可以从其他的域名注入他自己的ServiceWorker,然后篡改所有的请求——这无疑是非常危险的。

Service Worker 会响应三个事件:install,activate和fetch。

基于请求

直到这里,有一个反复出现的主题,您可能已经注意到。对数据库的每次操作,描述为通过一个请求打开数据库,访问一个object store,再继续。IndexedDB API天生是基于请求的,这也是API异步本性指示。对于你在数据库执行的每次操作,你必须首先为这个操作创建一个请求。当请求完成,你可以响应由请求结果产生的事件和错误。

本文实现的代码,演示了如何使用请求打开数据库,创建一个事务,读取object store的内容,写入object store,清空object store。

Install事件

该事件将在应用安装完成后触发。我们一般在这里使用Cache API缓存一些必要的文件。

首先,我们需要提供如下配置

  1. 缓存名称(CACHE)以及版本(version)。应用可以有多个缓存存储,但是在使用时只会使用其中一个缓存存储。每当缓存存储有变化时,新的版本号将会指定到缓存存储中。新的缓存存储将会作为当前的缓存存储,之前的缓存存储将会被作废。
  2. 一个离线的页面地址(offlineURL):当用户访问了之前没有访问过的地址时,该页面将会显示。
  3. 一个包含了所有必须文件的数组,包括保障页面正常功能的CSS和JavaScript。在本示例中,我还添加了主页和logo。当有不同的URL指向同一个资源时,你也可以将这些URL分别写到这个数组中。offlineURL将会加入到这个数组中。
  4. 我们也可以将一些非必要的缓存文件(installFilesDesirable)。这些文件在安装过程中将会被下载,但如果下载失败,不会触发安装失败。

// 配置文件 const version = '1.0.0', CACHE = version '::PWAsite', offlineURL = '/offline/', installFilesEssential = [ '/', '/manifest.json', '/css/styles.css', '/js/main.js', '/js/offlinepage.js', '/images/logo/logo152.png' ].concat(offlineURL), installFilesDesirable = [ '/favicon.ico', '/images/logo/logo016.png', '/images/hero/power-pv.jpg', '/images/hero/power-lo.jpg', '/images/hero/power-hi.jpg' ];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 配置文件
const
  version = '1.0.0',
  CACHE = version '::PWAsite',
  offlineURL = '/offline/',
  installFilesEssential = [
    '/',
    '/manifest.json',
    '/css/styles.css',
    '/js/main.js',
    '/js/offlinepage.js',
    '/images/logo/logo152.png'
  ].concat(offlineURL),
  installFilesDesirable = [
    '/favicon.ico',
    '/images/logo/logo016.png',
    '/images/hero/power-pv.jpg',
    '/images/hero/power-lo.jpg',
    '/images/hero/power-hi.jpg'
  ];

installStaticFiles() 方法使用基于Promise的方式使用Cache API将文件存储到缓存中。

// 安装静态资源 function installStaticFiles() { return caches.open(CACHE) .then(cache => { // 缓存可选文件 cache.addAll(installFilesDesirable); // 缓存必须文件 return cache.addAll(installFilesEssential); }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 安装静态资源
function installStaticFiles() {
  return caches.open(CACHE)
    .then(cache => {
      // 缓存可选文件
      cache.addAll(installFilesDesirable);
      // 缓存必须文件
      return cache.addAll(installFilesEssential);
    });
}

最后,我们添加一个install的事件监听器。waitUntil方法保证了service worker不会安装直到其相关的代码被执行。这里它会执行installStaticFiles()方法,然后self.skipWaiting()方法来激活service worker:

// 应用安装 self.addEventListener('install', event => { console.log('service worker: install'); // 缓存主要文件 event.waitUntil( installStaticFiles() .then(() => self.skipWaiting()) ); });

1
2
3
4
5
6
7
8
9
10
11
12
// 应用安装
self.addEventListener('install', event => {
  console.log('service worker: install');
  // 缓存主要文件
  event.waitUntil(
    installStaticFiles()
    .then(() => self.skipWaiting())
  );
});

打开数据库的请求生命周期

IndexedDB使用事件生命周期管理数据库的打开和配置操作。图2演示了一个打开的请求在一定的环境下产生upgrade need事件。

图片 5

图2:IndexedDB打开请求的生命周期

所有与数据库的交互开始于一个打开的请求。试图打开数据库时,您必须传递一个被请求数据库的版本号的整数值。在打开请求时,浏览器对比你传入的用于打开请求的版本号与实际数据库的版本号。如果所请求的版本号高于浏览器中当前的版本号(或者现在没有存在的数据库),upgrade needed事件触发。在uprade need事件期间,你有机会通过添加或移除stores,键和索引来操纵object stores。

如果所请求的数据库版本号和浏览器的当前版本号一致,或者升级过程完成,一个打开的数据库将返回给调用者。

Activate 事件

这个事件会在service worker被激活时发生。你可能不需要这个事件,但是在示例代码中,我们在该事件发生时将老的缓存全部清理掉了:

// clear old caches function clearOldCaches() { return caches.keys() .then(keylist => { return Promise.all( keylist .filter(key => key !== CACHE) .map(key => caches.delete(key)) ); }); } // application activated self.addEventListener('activate', event => { console.log('service worker: activate'); // delete old caches event.waitUntil( clearOldCaches() .then(() => self.clients.claim()) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// clear old caches
function clearOldCaches() {
  return caches.keys()
    .then(keylist => {
      return Promise.all(
        keylist
          .filter(key => key !== CACHE)
          .map(key => caches.delete(key))
      );
    });
}
// application activated
self.addEventListener('activate', event => {
  console.log('service worker: activate');
    // delete old caches
  event.waitUntil(
    clearOldCaches()
    .then(() => self.clients.claim())
    );
});

注意self.clients.claim()执行时将会把当前service worker作为被激活的worker。

Fetch 事件 该事件将会在网络开始请求时发起。该事件处理函数中,我们可以使用respondWith()方法来劫持HTTP的GET请求然后返回:

  1. 从缓存中取到的资源文件
  2. 如果第一步失败,资源文件将会从网络中使用Fetch API来获取(和service worker中的fetch事件无关)。获取到的资源将会加入到缓存中。
  3. 如果第一步和第二步均失败,将会从缓存中返回正确的资源文件。

// application fetch network data self.addEventListener('fetch', event => { // abandon non-GET requests if (event.request.method !== 'GET') return; let url = event.request.url; event.respondWith( caches.open(CACHE) .then(cache => { return cache.match(event.request) .then(response => { if (response) { // return cached file console.log('cache fetch: ' url); return response; } // make network request return fetch(event.request) .then(newreq => { console.log('network fetch: ' url); if (newreq.ok) cache.put(event.request, newreq.clone()); return newreq; }) // app is offline .catch(() => offlineAsset(url)); }); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// application fetch network data
self.addEventListener('fetch', event => {
  // abandon non-GET requests
  if (event.request.method !== 'GET') return;
  let url = event.request.url;
  event.respondWith(
    caches.open(CACHE)
      .then(cache => {
        return cache.match(event.request)
          .then(response => {
            if (response) {
              // return cached file
              console.log('cache fetch: ' url);
              return response;
            }
            // make network request
            return fetch(event.request)
              .then(newreq => {
                console.log('network fetch: ' url);
                if (newreq.ok) cache.put(event.request, newreq.clone());
                return newreq;
              })
              // app is offline
              .catch(() => offlineAsset(url));
          });
      })
  );
});

offlineAsset(url)方法中使用了一些helper方法来返回正确的数据:

// 是否为图片地址? let iExt = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp'].map(f => '.' f); function isImage(url) { return iExt.reduce((ret, ext) => ret || url.endsWith(ext), false); } // return 返回离线资源 function offlineAsset(url) { if (isImage(url)) { // 返回图片 return new Response( '<svg role="img" viewBox="0 0 400 300" xmlns=" d="M0 0h400v300H0z" fill="#eee" /><text x="200" y="150" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="50" fill="#ccc">offline</text></svg>', { headers: { 'Content-Type': 'image/svg xml', 'Cache-Control': 'no-store' }} ); } else { // return page return caches.match(offlineURL); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 是否为图片地址?
let iExt = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp'].map(f => '.' f);
function isImage(url) {
  
  return iExt.reduce((ret, ext) => ret || url.endsWith(ext), false);
  
}
  
  
// return 返回离线资源
function offlineAsset(url) {
  
  if (isImage(url)) {
  
    // 返回图片
    return new Response(
      '<svg role="img" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg"><title>offline</title><path d="M0 0h400v300H0z" fill="#eee" /><text x="200" y="150" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="50" fill="#ccc">offline</text></svg>',
      { headers: {
        'Content-Type': 'image/svg xml',
        'Cache-Control': 'no-store'
      }}
    );
  
  }
  else {
  
    // return page
    return caches.match(offlineURL);
  
  }
  
}

offlineAsset()方法检查请求是否为一个图片,然后返回一个带有“offline”文字的SVG文件。其他请求将会返回 offlineURL 页面。

Chrome开发者工具中的ServiceWorker部分提供了关于当前页面worker的信息。其中会显示worker中发生的错误,还可以强制刷新,也可以让浏览器进入离线模式。

Cache Storage 部分例举了当前所有已经缓存的资源。你可以在缓存需要更新的时候点击refresh按钮。

本文由千赢国际官网发布于千赢网页手机版登入,转载请注明出处:前端的数据库,入门教程

关键词: 千赢国际官网 千亿国际qy8.vip