国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
改造你的網(wǎng)站,變身 PWA

最近有很多關(guān)于 Progressive Web Apps(PWAs)的消息,很多人都在問(wèn)這是不是(移動(dòng))web 的未來(lái)。我不想陷入native app 和 PWA 的紛爭(zhēng),但是有一件事是確定的 --- PWA極大的提升了移動(dòng)端表現(xiàn),改善了用戶體驗(yàn)。

好消息是開發(fā)一個(gè) PWA 并不難。事實(shí)上,我們可以將現(xiàn)存的網(wǎng)站進(jìn)行改進(jìn),使之成為PWA。這也是我這篇文章要講的 -- 當(dāng)你讀完這篇文章,你可以將你的網(wǎng)站改進(jìn),讓他看起來(lái)就像是一個(gè) native web app。他可以離線工作并且擁有自己的主屏圖標(biāo)。

Progressive Web Apps 是什么?

Progressive Web Apps (下文以“PWAs”代指) 是一個(gè)令人興奮的前端技術(shù)的革新。PWAs綜合了一系列技術(shù)使你的 web app表現(xiàn)得就像是 native mobile app。相比于純 web 解決方案和純 native 解決方案,PWAs對(duì)于開發(fā)者和用戶有以下優(yōu)點(diǎn):

  1. 你只需要基于開放的 W3C 標(biāo)準(zhǔn)的 web 開發(fā)技術(shù)來(lái)開發(fā)一個(gè)app。不需要多客戶端開發(fā)。

  2. 用戶可以在安裝前就體驗(yàn)?zāi)愕?app。

  3. 不需要通過(guò) AppStore 下載 app。app 會(huì)自動(dòng)升級(jí)不需要用戶升級(jí)。

  4. 用戶會(huì)受到‘安裝’的提示,點(diǎn)擊安裝會(huì)增加一個(gè)圖標(biāo)到用戶首屏。

  5. 被打開時(shí),PWA 會(huì)展示一個(gè)有吸引力的閃屏。

  6. chrome 提供了可選選項(xiàng),可以使 PWA 得到全屏體驗(yàn)。

  7. 必要的文件會(huì)被本地緩存,因此會(huì)比標(biāo)準(zhǔn)的web app 響應(yīng)更快(也許也會(huì)比native app響應(yīng)快)

  8. 安裝及其輕量 -- 或許會(huì)有幾百 kb 的緩存數(shù)據(jù)。

  9. 網(wǎng)站的數(shù)據(jù)傳輸必須是 https 連接。

  10. PWAs 可以離線工作,并且在網(wǎng)絡(luò)恢復(fù)時(shí)可以同步最新數(shù)據(jù)。

現(xiàn)在還處在 PWA 的早期,但已經(jīng)有 很多成功案例 。

PWA 技術(shù)目前被 Firefox,Chrome 和其他基于Blink內(nèi)核的瀏覽器支持。微軟正在努力在Edge瀏覽器上實(shí)現(xiàn)。Apple沒有動(dòng)作 although there are promising comments in the WebKit five-year plan。幸運(yùn)的是,瀏覽器支持對(duì)于 PWA 似乎不太重要...

PWAs 是漸進(jìn)增強(qiáng)的

你的app仍然可以運(yùn)行在不支持 PWA 技術(shù)的瀏覽器里。用戶不能離線訪問(wèn),不過(guò)其他功能都像原來(lái)一樣沒有影響。綜合利弊得失,沒有理由不把你的 app 改進(jìn)為 PWA。

不只是 Apps

Google 引領(lǐng)了 PWA 的一系列動(dòng)作,所以大多數(shù)教程都在說(shuō)如何從零開始構(gòu)建一個(gè)基于 Chrome,native-looking mobile app。然而并不是只有特殊的單頁(yè)應(yīng)用可以PWA化,也不需要一定遵循 material interface design guidelines。大多數(shù)網(wǎng)站都可以在數(shù)小時(shí)內(nèi)實(shí)現(xiàn) PWA 化。這包括你的 WordPress站點(diǎn)或者靜態(tài)站點(diǎn)。

示例代碼

示例代碼可以在https://github.com/sitepoint-editors/pwa-retrofit找到。

代碼提供了一個(gè)簡(jiǎn)單的四個(gè)頁(yè)面的網(wǎng)站。其中包含一些圖片,一個(gè)樣式表和一個(gè)main javascript 文件。這個(gè)網(wǎng)站可以運(yùn)行在所有現(xiàn)代瀏覽器上(IE10+)。如果瀏覽器支持 PWA 技術(shù),當(dāng)離線時(shí)用戶可以瀏覽他們之前看過(guò)的頁(yè)面。

運(yùn)行代碼前,確保 Node.js 已經(jīng)安裝,然后再命令行里啟動(dòng)服務(wù):

node ./server.js [port]

[port]是可配置的,默認(rèn)為 8888。打開 Chrome 或者其他基于Blink內(nèi)核的瀏覽器,比如 Opera 或者 Vivaldi,然后輸入鏈接 http://localhost:8888/(或者你指定的某個(gè)端口)。你也可以打開開發(fā)者工具看一下各個(gè)console信息。

瀏覽主頁(yè),或者其他頁(yè)面,然后用以下任一方法使頁(yè)面離線:

  1. 按下 Cmd/Ctrl + C ,停止 node 服務(wù)器,或者

  2. 在開發(fā)者工具的 Network 或者 Application - Service Workers 欄里點(diǎn)擊 offline 選項(xiàng)。

重新瀏覽任意之前瀏覽過(guò)的頁(yè)面,它們?nèi)匀豢梢詾g覽到。瀏覽一個(gè)之前沒有看過(guò)的頁(yè)面,你會(huì)看到一個(gè)專門的離線頁(yè)面,標(biāo)識(shí)“you’re offline”,還有一個(gè)你可以瀏覽的頁(yè)面列表:

連接手機(jī)

你也可以通過(guò) USB 連接你的安卓手機(jī)來(lái)預(yù)覽示例網(wǎng)頁(yè)。在開發(fā)者工具中打開 Remote devices 菜單。

在左邊選擇 Settings ,點(diǎn)擊 Add Rule 輸入 8888 端口。你可以在你的手機(jī)上打開Chrome,打開 http://localhost:8888/

你可以點(diǎn)擊瀏覽器菜單里的 “Add to Home screen”。瀏覽幾個(gè)頁(yè)面,瀏覽器會(huì)提醒你去安裝。這兩種方式都可以創(chuàng)建一個(gè)新的圖標(biāo)在你的主屏上。瀏覽幾個(gè)頁(yè)面后關(guān)掉Chrome,斷開設(shè)備連接。你依然可以打開 PWA Website app -- 你會(huì)看到一個(gè)啟動(dòng)頁(yè),并且可以離線訪問(wèn)之前你訪問(wèn)過(guò)的頁(yè)面。

將你的網(wǎng)站改進(jìn)為一個(gè) Progressive Web App 總共有三個(gè)必要步驟:

第一步:開啟 HTTPS

由于一些顯而易見的原因,PWAs 需要 HTTPS 連接。

HTTPS 在示例代碼中并不是必須的,因?yàn)?Chrome 允許使用 localhost 或者任何 127.x.x.x 的地址來(lái)測(cè)試。你也可以在 HTTP 連接下測(cè)試你的 PWA,你需要使用 Chrome ,并且輸入以下命令行參數(shù):

  • --user-data-dir

  • --unsafety-treat-insecure-origin-as-secure

第二步:創(chuàng)建一個(gè) Web App Manifest

manifest 文件提供了一些我們網(wǎng)站的信息,例如 name,description 和需要在主屏使用的圖標(biāo)的圖片,啟動(dòng)屏的圖片等。

manifest文件是一個(gè) JSON 格式的文件,位于你項(xiàng)目的根目錄。它必須用Content-Type: application/manifest+json 或者 Content-Type: application/json 這樣的 HTTP 頭來(lái)請(qǐng)求。這個(gè)文件可以被命名為任何名字,在示例代碼中他被命名為 /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"    }  ]}

在頁(yè)面的<head>中引入:

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

manifest 中主要屬性有:

  • name —— 網(wǎng)頁(yè)顯示給用戶的完整名稱

  • short_name —— 當(dāng)空間不足以顯示全名時(shí)的網(wǎng)站縮寫名稱

  • description —— 關(guān)于網(wǎng)站的詳細(xì)描述

  • start_url —— 網(wǎng)頁(yè)的初始 相對(duì) URL(比如 /

  • scope —— 導(dǎo)航范圍。比如,/app/的scope就限制 app 在這個(gè)文件夾里。

  • background-color —— 啟動(dòng)屏和瀏覽器的背景顏色

  • theme_color —— 網(wǎng)站的主題顏色,一般都與背景顏色相同,它可以影響網(wǎng)站的顯示

  • orientation —— 首選的顯示方向:any, natural, landscape, landscape-primary, landscape-secondary, portrait, portrait-primary, 和 portrait-secondary

  • display —— 首選的顯示方式:fullscreen, standalone(看起來(lái)像是native app),minimal-ui(有簡(jiǎn)化的瀏覽器控制選項(xiàng)) 和 browser(常規(guī)的瀏覽器 tab)

  • icons —— 定義了 src URL, sizestype的圖片對(duì)象數(shù)組。

MDN提供了完整的manifest屬性列表:Web App Manifest properties

在開發(fā)者工具中的 Application tab 左邊有 Manifest 選項(xiàng),你可以驗(yàn)證你的 manifest JSON 文件,并提供了 “Add to homescreen”。

第三步:創(chuàng)建一個(gè) Service Worker

Service Worker 是攔截和響應(yīng)你的網(wǎng)絡(luò)請(qǐng)求的編程接口。這是一個(gè)位于你根目錄的一個(gè)單獨(dú)的 javascript 文件。

你的 js 文件(在示例代碼中是 /js/main.js)可以檢查是否支持 Service Worker,并且注冊(cè):

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

如果你不需要離線功能,可以簡(jiǎn)單的創(chuàng)建一個(gè)空的 /service-worker.js文件 —— 用戶會(huì)被提示安裝你的 app。

Service Worker 很復(fù)雜,你可以修改示例代碼來(lái)達(dá)到自己的目的。這是一個(gè)標(biāo)準(zhǔn)的 web worker,瀏覽器用一個(gè)單獨(dú)的線程來(lái)下載和執(zhí)行它。它沒有調(diào)用 DOM 和其他頁(yè)面 api 的能力,但他可以攔截網(wǎng)絡(luò)請(qǐng)求,包括頁(yè)面切換,靜態(tài)資源下載,ajax請(qǐng)求所引起的網(wǎng)絡(luò)請(qǐng)求。

這就是需要 HTTPS 的最主要的原因。想象一下第三方代碼可以攔截來(lái)自其他網(wǎng)站的 service worker, 將是一個(gè)災(zāi)難。

service worker 主要有三個(gè)事件: install,activatefetch

Install 事件

這個(gè)事件在app被安裝時(shí)觸發(fā)。它經(jīng)常用來(lái)緩存必要的文件。緩存通過(guò) Cache API來(lái)實(shí)現(xiàn)。

首先,我們來(lái)構(gòu)造幾個(gè)變量:

  1. 緩存名稱(CACHE)和版本號(hào)(version)。你的應(yīng)用可以有多個(gè)緩存但是只能引用一個(gè)。我們?cè)O(shè)置了版本號(hào),這樣當(dāng)我們有重大更新時(shí),我們可以更新緩存,而忽略舊的緩存。

  2. 一個(gè)離線頁(yè)面的URL(offlineURL)。當(dāng)離線時(shí)用戶試圖訪問(wèn)之前未緩存的頁(yè)面時(shí),這個(gè)頁(yè)面會(huì)呈現(xiàn)給用戶。

  3. 一個(gè)擁有離線功能的頁(yè)面必要文件的數(shù)組(installFilesEssential)。這個(gè)數(shù)組應(yīng)該包含靜態(tài)資源,比如 CSS 和 JavaScript 文件,但我也把主頁(yè)面(/)和圖標(biāo)文件寫進(jìn)去了。如果主頁(yè)面可以多個(gè)URL訪問(wèn),你應(yīng)該把他們都寫進(jìn)去,比如//index.html。注意,offlineURL也要被寫入這個(gè)數(shù)組。

  4. 可選的,描述文件數(shù)組(installFilesDesirable)。這些文件都很會(huì)被下載,但如果下載失敗不會(huì)中止安裝。

// configurationconst  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()方法添加文件到緩存,這個(gè)方法用到了基于 promise的 Cache API。當(dāng)必要的文件都被緩存后才會(huì)生成返回值。

// install static assetsfunction installStaticFiles() {  return caches.open(CACHE)    .then(cache => {      // cache desirable files      cache.addAll(installFilesDesirable);      // cache essential files      return cache.addAll(installFilesEssential);    });}

最后,我們添加install的事件監(jiān)聽函數(shù)。 waitUntil方法確保所有代碼執(zhí)行完畢后,service worker 才會(huì)執(zhí)行 install。執(zhí)行 installStaticFiles()方法,然后執(zhí)行 self.skipWaiting()方法使service worker進(jìn)入 active狀態(tài)。

// application installationself.addEventListener('install', event => {  console.log('service worker: install');  // cache core files  event.waitUntil(    installStaticFiles()    .then(() => self.skipWaiting())  );});

Activate 事件

當(dāng) install完成后, service worker 進(jìn)入active狀態(tài),這個(gè)事件立刻執(zhí)行。你可能不需要實(shí)現(xiàn)這個(gè)事件監(jiān)聽,但是示例代碼在這里刪除老舊的無(wú)用緩存文件:

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

注意,最后的self.clients.claim()方法設(shè)置本身為active的service worker。

Fetch 事件

當(dāng)有網(wǎng)絡(luò)請(qǐng)求時(shí)這個(gè)事件被觸發(fā)。它調(diào)用respondWith()方法來(lái)劫持 GET 請(qǐng)求并返回:

  1. 緩存中的一個(gè)靜態(tài)資源。

  2. 如果 #1 失敗了,就用 Fetch API(這與 service worker 的fetch 事件沒關(guān)系)去網(wǎng)絡(luò)請(qǐng)求這個(gè)資源。然后將這個(gè)資源加入緩存。

  3. 如果 #1 和 #2 都失敗了,那就返回一個(gè)適當(dāng)?shù)闹怠?/p>

// application fetch network dataself.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));          });      })  );});

最后這個(gè)offlineAsset(url)方法通過(guò)幾個(gè)輔助函數(shù)返回一個(gè)適當(dāng)?shù)闹担?/p>

// is image URL?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 offline assetfunction offlineAsset(url) {  if (isImage(url)) {    // return image    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()方法檢查是否是一個(gè)圖片請(qǐng)求,如果是,那么返回一個(gè)帶有 “offline” 字樣的 SVG。如果不是,返回 offlineURL 頁(yè)面。

開發(fā)者工具提供了查看 Service Worker 相關(guān)信息的選項(xiàng):

在開發(fā)者工具的 Cache Storage 選項(xiàng)列出了所有當(dāng)前域內(nèi)的緩存和所包含的靜態(tài)文件。當(dāng)緩存更新的時(shí)候,你可以點(diǎn)擊左下角的刷新按鈕來(lái)更新緩存:

不出意料, Clear storage 選項(xiàng)可以刪除你的 service worker 和緩存:

再來(lái)一步 - 第四步:創(chuàng)建一個(gè)可用的離線頁(yè)面

離線頁(yè)面可以是一個(gè)靜態(tài)頁(yè)面,來(lái)說(shuō)明當(dāng)前用戶請(qǐng)求不可用。然而,我們也可以在這個(gè)頁(yè)面上列出可以訪問(wèn)的頁(yè)面鏈接。

main.js中我們可以使用 Cache API 。然而API 使用promises,在不支持的瀏覽器中會(huì)引起所有javascript運(yùn)行阻塞。為了避免這種情況,我們?cè)诩虞d另一個(gè) /js/offlinepage.js 文件之前必須檢查離線文件列表和是否支持 Cache API 。

// load script to populate offline page listif (document.getElementById('cachedpagelist') && 'caches' in window) {  var scr = document.createElement('script');  scr.src = '/js/offlinepage.js';  scr.async = 1;  document.head.appendChild(scr);}

/js/offlinepage.js locates the most recent cache by version name, 取到所有 URL的key的列表,移除所有無(wú)用 URL,排序所有的列表并且把他們加到 ID 為cachedpagelist的 DOM 節(jié)點(diǎn)中:

// cache nameconst  CACHE = '::PWAsite',  offlineURL = '/offline/',  list = document.getElementById('cachedpagelist');// fetch all cacheswindow.caches.keys()  .then(cacheList => {    // find caches by and order by most recent    cacheList = cacheList      .filter(cName => cName.includes(CACHE))      .sort((a, b) => a - b);    // open first cache    caches.open(cacheList[0])      .then(cache => {        // fetch cached pages        cache.keys()          .then(reqList => {            let frag = document.createDocumentFragment();            reqList              .map(req => req.url)              .filter(req => (req.endsWith('/') || req.endsWith('.html')) && !req.endsWith(offlineURL))              .sort()              .forEach(req => {                let                  li = document.createElement('li'),                  a = li.appendChild(document.createElement('a'));                  a.setAttribute('href', req);                  a.textContent = a.pathname;                  frag.appendChild(li);              });            if (list) list.appendChild(frag);          });      })  });

開發(fā)工具

如果你覺得 javascript 調(diào)試?yán)щy,那么 service worker 也不會(huì)很好。Chrome的開發(fā)者工具的 Application 提供了一系列調(diào)試工具。

你應(yīng)該打開 隱身窗口 來(lái)測(cè)試你的 app,這樣在你關(guān)閉這個(gè)窗口之后緩存文件就不會(huì)保存下來(lái)。

最后,Lighthouse extension for Chrome 提供了很多改進(jìn) PWA 的有用信息。

PWA 陷阱

有幾點(diǎn)需要注意:

URL 隱藏

我們的示例代碼隱藏了 URL 欄,我不推薦這種做法,除非你有一個(gè)單 url 應(yīng)用,比如一個(gè)游戲。對(duì)于多數(shù)網(wǎng)站,manifest 選項(xiàng) display: minimal-ui 或者 display: browser是最好的選擇。

緩存太多

你可以緩存你網(wǎng)站的所有頁(yè)面和所有靜態(tài)文件。這對(duì)于一個(gè)小網(wǎng)站是可行的,但這對(duì)于上千個(gè)頁(yè)面的大型網(wǎng)站實(shí)際嗎?沒有人會(huì)對(duì)你網(wǎng)站的所有內(nèi)容都感興趣,而設(shè)備的內(nèi)存容量將是一個(gè)限制。即使你像示例代碼一樣只緩存訪問(wèn)過(guò)的頁(yè)面和文件,緩存大小也會(huì)增長(zhǎng)的很快。

也許你需要注意:

  • 只緩存重要的頁(yè)面,類似主頁(yè),和最近的文章。

  • 不要緩存圖片,視頻和其他大型文件

  • 經(jīng)常刪除舊的緩存文件

  • 提供一個(gè)緩存按鈕給用戶,讓用戶決定是否緩存

緩存刷新

在示例代碼中,用戶在請(qǐng)求網(wǎng)絡(luò)前先檢查該文件是否緩存。如果緩存,就使用緩存文件。這在離線情況下很棒,但也意味著在聯(lián)網(wǎng)情況下,用戶得到的可能不是最新數(shù)據(jù)。

靜態(tài)文件,類似于圖片和視頻等,不會(huì)經(jīng)常改變的資源,做長(zhǎng)時(shí)間緩存沒有很大的問(wèn)題。你可以在HTTP 頭里設(shè)置 Cache-Control 來(lái)緩存文件使其緩存時(shí)間為一年(31,536,000 seconds):

Cache-Control: max-age=31536000

頁(yè)面,CSS和 script 文件會(huì)經(jīng)常變化,所以你應(yīng)該改設(shè)置一個(gè)很短的緩存時(shí)間比如 24 小時(shí),并在聯(lián)網(wǎng)時(shí)與服務(wù)端文件進(jìn)行驗(yàn)證:

Cache-Control: must-revalidate, max-age=86400

譯自 Retrofit Your Website as a Progressive Web App

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Service Worker
開發(fā)一個(gè)漸進(jìn)式Web應(yīng)用程序(PWA)前都需要了解什么?
面向.NET開發(fā)人員的Dapr——入門
Node.js基礎(chǔ)入門第四天
人們常說(shuō)的前端工程化到底是什么?
通過(guò)一個(gè)簡(jiǎn)單的 Node.js 文件上傳應(yīng)用程序來(lái)了解 IBM Bluemix
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服