手把手教你制作一个PWA应用教程
來源 |?https://segmentfault.com/a/1190000019414253
簡介
Web前端的同學(xué)是否想過學(xué)習(xí)應(yīng)用開發(fā),以彌補(bǔ)自己的移動(dòng)端能力的不足?但在面對一眾的選擇時(shí)很多同學(xué)略感迷茫,是學(xué)習(xí)ios還是android開發(fā)?是學(xué)習(xí)原生開發(fā),混合開發(fā)(例如:Ionic),還是使用react native或者flutter這樣的跨平臺(tái)框架?而應(yīng)用開發(fā)的學(xué)習(xí)周期長,學(xué)習(xí)成本高也讓一部分人望而卻步。
得益于前端技術(shù)的飛速發(fā)展,瀏覽器性能的不斷提高,使用網(wǎng)頁技術(shù)開發(fā)出接近原生體驗(yàn)的應(yīng)用重新實(shí)現(xiàn)的現(xiàn)實(shí),PWA就在這樣的背景下應(yīng)運(yùn)而生。可以用自己熟悉的HTML,CSS,Javascript開發(fā)出替代美原生應(yīng)用的網(wǎng)站,而擁有接近原生應(yīng)用的流暢程度,并且某些某些原生app才有的特性,
例如:a。可以在主屏上安裝應(yīng)用圖標(biāo),b。離線狀態(tài)下訪問,c。獲取消息通知,等等。。PWA的出現(xiàn)讓大家看到了希望!
對比原生應(yīng)用
那分別PWA和原生應(yīng)用比例到底有何競爭力呢?我們分別看一下原生應(yīng)用和PWA的特點(diǎn):
原生應(yīng)用:
使用原生SDK和開發(fā)工具開發(fā)
需要考慮跨平臺(tái),不同系統(tǒng)經(jīng)常需要獨(dú)立開發(fā)
需要發(fā)布到應(yīng)用商店才能下載使用
可以安裝到手機(jī)主屏,生成應(yīng)用圖標(biāo)
直接運(yùn)行于操作系統(tǒng)上,訪問系統(tǒng)資源方便
可以離線使用
可以獲取消息通知
PWA應(yīng)用:
使用HTML,CSS,JS開發(fā)
無需考慮跨平臺(tái),只需要考慮瀏覽器兼容性
通過網(wǎng)址訪問,無需發(fā)布到應(yīng)用商店
可以安裝到手機(jī)主屏,生成應(yīng)用圖標(biāo)
運(yùn)行于瀏覽器中,可訪問系統(tǒng)資源
可以離線使用
可以獲取消息通知
可以發(fā)現(xiàn)PWA本質(zhì)上是原生應(yīng)用的主要能力,但是開發(fā)流程卻比原生應(yīng)用更加簡潔:
a、html / css / js的群眾基礎(chǔ)更好,開發(fā)效率更高;
b、省去了為不同系統(tǒng)開發(fā)獨(dú)立版本的大量成本;
c、省去了上架到應(yīng)用市場的繁瑣流程;
d、無需進(jìn)一步應(yīng)用商店下載,用戶使用起來也更加方便。但是稍微的是,PWA還是相對比較新的技術(shù),實(shí)現(xiàn)規(guī)范還有很多調(diào)整的空間,部分瀏覽器對PWA的支持也還不完善,但是PWA是一個(gè)趨勢,所以現(xiàn)在學(xué)習(xí)正合適!
本文將通過一個(gè)簡單的列子(一個(gè)簡單的郵編查詢應(yīng)用)向大家展示PWA的開發(fā)流程,項(xiàng)目參考:Traversy Media-使用Vue和Ionic4構(gòu)建PWA。完成后的效果是這樣的。
創(chuàng)建項(xiàng)目
項(xiàng)目使用Vue + Ionic的組合進(jìn)行開發(fā)。此處主要關(guān)注PWA的構(gòu)造,因此vue,ionic等技術(shù)不做過多描述。使用VSCode的同學(xué),建議安裝Vetur插件提高開發(fā)效率。
1.首先大致安裝@vue/cli:
npm install -g @vue/cli2.初始化vue項(xiàng)目:
3.因?yàn)閕onic的vue-router路由依賴于,所以接下來安裝vue-router:
4.安裝?@ionic/vue
npm install @ionic/vue5.在src/main.js中添加對ionic的
6.在src/router.js中使用IonicVueRouter替換預(yù)設(shè)的vue路由器:
import Vue from 'vue'import { IonicVueRouter } from '@ionic/vue';import Home from './views/Home.vue' Vue.use(IonicVueRouter) export default new IonicVueRouter({ mode: 'history', base: process.env.BASE_URL, routes: [ { path: '/', name: 'home', component: Home } ]})7.將src/App.vue內(nèi)容修改為:
<template> <div id="app"> <ion-app> <ion-vue-router/> </ion-app> </div></template>8.將src/views/Home.vue內(nèi)容修改為:
<template> <div class="ion-page"> <ion-header> <ion-toolbar> <ion-title> ZipInfo </ion-title> </ion-toolbar> </ion-header> <ion-content class="ion-padding">My App</ion-content> </div></template> <script>export default { name: 'home', components: {}}</script>最后,我們運(yùn)行yarn serve看下效果:
App功能實(shí)現(xiàn)
App主要有三部分組成:1。搜索組件,用于輸入郵編并查詢,2。展示組件,用于展示查詢到的郵編信息,3。清除按鈕,用于清除查詢到的郵編信息
1、搜索組件
我們在src/components下面的新建ZipSearch.vue文件作為郵編搜索組件,主要邏輯為當(dāng)用戶輸入一串字符,點(diǎn)擊搜索按鈕,如果輸入合法則觸發(fā)get-zip事件,如果不合法則提示。
ZipSearch.vue
<template> <ion-grid> <form @submit="onSubmit"> <ion-col> <ion-item> <ion-label>ZipCode:</ion-label> <ion-input :value="zip" @input="zip = $event.target.value" name="zip" placeholder="Enter US ZipCode" /> </ion-item> </ion-col> <ion-col> <ion-button type="submit" color="primary" expand="block">Find</ion-button> </ion-col> </form> </ion-grid></template> <script>export default { name: "ZipSearch", data() { return { zip: "" }; }, methods: { onSubmit(e) { e.preventDefault(); const zipRegex = /(^\d{5}$)|(^\d{5}-\d{4}$)/; const isValid = zipRegex.test(this.zip); if (!isValid) { this.showAlert(); } else { this.$emit("get-zip", this.zip); } this.zip = ""; }, showAlert() { return this.$ionic.alertController .create({ header: "Enter zipcode", message: "Please enter a valid US ZipCode", buttons: ["OK"] }) .then(a => a.present()); } }};</script>在src/views/Home.vue中約會(huì)ZipSearch組件,當(dāng)Home接收到get-zip事件時(shí)調(diào)用https://www.zippopotam.us的接口,獲取郵編對應(yīng)的信息:
... <ion-content class="ion-padding"> <ZipSearch v-on:get-zip="getZipInfo"/> </ion-content>... <script>import ZipSearch from "../components/ZipSearch"; export default { name: "home", components: { ZipSearch }, data() { return { info: null }; }, methods: { async getZipInfo(zip) { const res = await fetch(`https://api.zippopotam.us/us/${zip}`); if (res.status == 404) { this.showAlert(); } this.info = await res.json(); }, showAlert() { return this.$ionic.alertController .create({ header: "Not Valid", message: "Please enter a valid US ZipCode", buttons: ["OK"] }) .then(a => a.present()); } }};</script>我們先看一下搜索組件的效果:
輸入郵編格式錯(cuò)誤:
2、信息展示和清除組件
獲取到郵編信息后我們需要一個(gè)展示郵編信息的組件和一個(gè)src/components清除信息的按鈕,在下面新建ZipInfo.vue和ClearInfo.vue。
ZipInfo.vue
<template> <ion-card v-if="info"> <ion-card-header> <ion-card-subtitle>{{info['post code']}}</ion-card-subtitle> <ion-card-title>{{info['places'][0]['place name']}}</ion-card-title> </ion-card-header> <ion-card-content> <ion-list> <ion-item> <ion-label> <strong>State:</strong> {{info['places'][0]['state']}} ({{info['places'][0]['state abbreviation']}}) </ion-label> </ion-item> <ion-item> <ion-label> <strong>Latitude:</strong> {{info['places'][0]['latitude']}} </ion-label> </ion-item> <ion-item> <ion-label> <strong>Longitude:</strong> {{info['places'][0]['longitude']}} </ion-label> </ion-item> </ion-list> </ion-card-content> </ion-card></template> <script>export default { name: "ZipInfo", props: ["info"]};</script>ClearInfo.vue
<template> <ion-button color="light" expand="block" v-if="info" @click="$emit('clear-info')">Clear</ion-button></template> <script>export default { name: "ClearInfo", props: ["info"]};</script>接著在Home中約會(huì)ZipInfo和ClearInfo組件:
src / views / Home.vue
... <ion-content class="ion-padding"> <ZipSearch v-on:get-zip="getZipInfo"/> <ZipInfo v-bind:info="info"/> <ClearInfo v-bind:info="info" v-on:clear-info="clearInfo"/> </ion-content>... import ZipInfo from "../components/ZipInfo";import ClearInfo from "../components/ClearInfo"; export default { name: "home", components: { ZipSearch, ZipInfo }, methods:{ ... clearInfo(){ this.info = null; } }}到此,app的主體就完成了,效果如下:
實(shí)現(xiàn)PWA
我們使用現(xiàn)成的@vue/pwa插件來給我們的app增加PWA的能力。
安裝@vue/pwa:
vue add @vue/pwa安裝完成后項(xiàng)目中增加了public/manifest.json和registerServiceWorker.js兩個(gè)文件。其中public/manifest.json文件內(nèi)容如下:
{ "name": "vue-ionic-pwa", "short_name": "vue-ionic-pwa", "icons": [ { "src": "./img/icons/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "./img/icons/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" } ], "start_url": "./index.html", "display": "standalone", "background_color": "#000000", "theme_color": "#4DBA87"}manifest.json中主要包含app的基本信息,例如名稱(名稱),圖標(biāo)(圖標(biāo)),顯示方式(display)等等,是web app能被以類似原生的方式安裝,展示的必要配置。更多的配置項(xiàng)可參考MDN Web App清單。
在Chrome瀏覽器控制臺(tái)中也可看到app的manifest配置:
registerServiceWorker.js為注冊服務(wù)人員。服務(wù)人員通俗地說就是在瀏覽器后臺(tái)獨(dú)立于網(wǎng)頁運(yùn)行的一段腳本,服務(wù)人員可以完成一些特殊的功能,例如:消息推送,后臺(tái)同步,攔截和處理網(wǎng)絡(luò)請求,管理網(wǎng)絡(luò)緩存等。Serviceworker之于pwa的意義在于能夠?yàn)橛脩籼峁╇x線體驗(yàn),即掉線狀態(tài)下用戶依舊能夠訪問網(wǎng)站并獲取已被緩存的數(shù)據(jù)。使用service worker需要HTTPS,并考慮瀏覽器兼容性。
registerServiceWorker.js
import { register } from 'register-service-worker' if (process.env.NODE_ENV === 'production') { register(`${process.env.BASE_URL}service-worker.js`, { ready () { console.log( 'App is being served from cache by a service worker.\n' + 'For more details, visit https://goo.gl/AFskqB' ) }, registered () { console.log('Service worker has been registered.') }, cached () { console.log('Content has been cached for offline use.') }, updatefound () { console.log('New content is downloading.') }, updated () { console.log('New content is available; please refresh.') }, offline () { console.log('No internet connection found. App is running in offline mode.') }, error (error) { console.error('Error during service worker registration:', error) } })}在Chrome瀏覽器控制臺(tái)中也可看到服務(wù)工作者的狀態(tài):
當(dāng)然,只注冊了service worker還不夠,我們還希望控制service worker的行為,通過在vue.config.js中增加相關(guān)的配置我們可以設(shè)置service worker文件的名稱,緩存邏輯等等。
vue.config.js
module.exports = { pwa: { workboxPluginMode: 'GenerateSW', workboxOptions: { navigateFallback: '/index.html', runtimeCaching: [ { urlPattern: new RegExp('^https://api.zippopotam.us/us/'), handler: 'networkFirst', options: { networkTimeoutSeconds: 20, cacheName: 'api-cache', cacheableResponse: { statuses: [0, 200] } } } ] } }}更多配置請參考:@ VUE / CLI-插件,PWA和針線-的WebPack-插件。由于@vue/cli-plugin-pwa,生成的服務(wù)人員只在生產(chǎn)環(huán)境生效,所以建議將項(xiàng)目建設(shè)之后部署到生產(chǎn)環(huán)境測試本文示例使用GitHub的頁面進(jìn)行部署和展示。
到此,將普通的網(wǎng)絡(luò)應(yīng)用轉(zhuǎn)成PWA的工作基本完成,我們部署到線上看下效果:
文件已被緩存用于離線訪問:
查詢一個(gè)郵編試試,可以發(fā)現(xiàn)請求被緩存了下來:
我們隨后關(guān)掉網(wǎng)絡(luò),再查詢剛剛的那個(gè)郵編,發(fā)現(xiàn)在網(wǎng)絡(luò)請求失敗之后立即切換用本地緩存的數(shù)據(jù):
好了,一個(gè)簡單的PWA就已經(jīng)制作完成了。當(dāng)然PWA的功能遠(yuǎn)不止此所展示的,依次按壓,安裝到手機(jī),后續(xù)有機(jī)會(huì)再跟大家分享,謝謝。
總結(jié)
以上是生活随笔為你收集整理的手把手教你制作一个PWA应用教程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CCRC信息安全服务资质认证流程和认证周
- 下一篇: C#仿matlab函数进行语音降噪(有b