Angular初探PWA

所谓PWA是 Progressive Web App 的缩写,中文意思是 “渐进式 Web 应用”,PWA有与传统的Web应用相比有什么优势?在《PWA开发实战》一书中列出了以下几点:

  • 无连接状态下的可用性
  • 加载速度快
  • 推送通知
  • 主屏幕快捷方式
  • 媲美原生
PWA开发实战封面

从渐进学习的角度,本文将初步探索使用Angular框架来实现PWA的“无连接状态下的可用性


准备工作

1、安装脚手架工具

$ npm install -g @angular/cli

2、创建项目,命名为 gotham-hotel 即《PWA开发实战》中的 哥谭帝国酒店

$ ng new gotham-hotel

...

$ cd gotham-hotel

3、初始化配置, 添加样式库,本项目选用 NG-ZORRO

$ ng add ng-zorro-antd

4、安装后端数据模拟工具 json-server

$ npm install --save-dev json-server

5、修改package.json文件,添加json-server的启动指令

...    
"scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "json": "json-server data.js -p 3500"
},
...

6、添加模拟数据:在package.json 同级目录添加 data.js 文件,文件中的 rooms 数组 模拟了 酒店的房型

module.exports = function () {
    return {
        rooms: [
            { id: '1', name: "标准房",
                description: "45-58㎡ 1张双人床 有wifi 有窗", price: 5959 },
            { id: '2', name: "城景两张大床房", 
                description: "46-58㎡ 2张双人床 有wifi 禁烟 有窗", price: 7340 },
            { id: '3', name: "一室特大床套房", 
                description: "65㎡ 1张双人床 有窗", price: 8487 },
            { id: '4', name: "露台套房",
                description: "94㎡ 1张双人床 有窗", price: 19755 },
        ],
    }
}

准备Angular控件和服务

1、创建房型 数据接口

$ ng g interface services/room

接口定义如下:

export interface Room {
    id: string;
    name: string;
    description: string;
    price: number;
}

2、创建 房型 数据获取服务

$ ng g s services/rooms

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

import { Room } from './room';

@Injectable({
  providedIn: 'root'
})
export class RoomsService {

  roomsUrl = `http://${location.hostname}:3500/rooms`;

  constructor(private http: HttpClient) { }

  getRooms(): Observable<Room[]> {
    return this.http.get<Room[]>(this.roomsUrl);
  }
}

3、创建房型列表组件, 用于展示房型信息

$ ng g c components/rooms

修改 rooms.component.ts 文件如下:

import { Component, OnInit } from '@angular/core';

import { Room } from '../../services/room';
import { RoomsService } from '../../services/rooms.service';

@Component({
  selector: 'app-rooms',
  templateUrl: './rooms.component.html',
  styleUrls: ['./rooms.component.css']
})
export class RoomsComponent implements OnInit {
  rooms: Room[];
  error: string;

  constructor(private roomsService: RoomsService) { }

  ngOnInit() {
    this.roomsService.getRooms()
      .subscribe(
        rooms => this.rooms = rooms,
        error => this.error = error.message
      );
  }
}

修改rooms.component.html文件如下:

<nz-list [nzDataSource]="rooms" [nzRenderItem]="item" [nzItemLayout]="'horizontal'">
  <ng-template #item let-item>
    <nz-list-item [nzActions]="[price]">
      <ng-template #price>
        <nz-tag nzColor="green">{{item.price | currency:'CNY'}}</nz-tag>
      </ng-template>
      <nz-list-item-meta
        [nzTitle]="nzTitle"
        [nzAvatar]="'assets/room' + item.id + '.png'"
        [nzDescription]="item.description"
      >
        <ng-template #nzTitle>
          {{ item.name }}
        </ng-template>
      </nz-list-item-meta>
    </nz-list-item>
  </ng-template>
</nz-list>
<h3 *ngIf="error">错误信息: {{error}}</h3>

4、创建 home 组件

$ ng g c components/home --inlineTemplate=true

修改 home.component.ts 文件如下

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-home',
  template: `
    <a nz-button nzType="primary" nzSize="large" routerLink="rooms">
      欢迎光临哥谭帝国酒店
    </a>
  `,
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }
}

5、设置路由
在 app.module.ts 文件内加入如下路由信息

...
RouterModule.forRoot([
      { path: '', component: HomeComponent},
      { path: 'rooms', component: RoomsComponent },
    ])
...

修改app.component.ts 文件如下 (注意,要自己把logo图片和 room1、2、3、4图片放到assets目录下)

<nz-row nzType="flex" nzJustify="center">
  <nz-col>
    <img src="assets/logo.png" routerLink="">
  </nz-col>
</nz-row>
<nz-row nzType="flex" nzJustify="center">
  <router-outlet></router-outlet>
</nz-row>

初步测试

1、启动模拟后端数据

$ npm run json

2、启动angular服务

$ ng serve --port 0 --open

如果一切没有问题的话,在浏览器中可以看到


首页

点击蓝色的按钮,可以进入房型列表页面


房型列表页

断线会如何?

到这里为止,一切都还只是一个常规的Web应用,让我们来模拟一下断线会出现什么情况

在 Chrome 中:

1、选择 Tools > Developer Tools (从右上角的 Chrome 菜单)。

2、进入 Network 页。

3、勾选Offline 复选框。


offline

刷新页面,小恐龙就会出现了


断线

PWA登场

做足了前戏,才轮到我们的主角上场了

1、安装pwa

$ ng add @angular/pwa

2、配置缓存信息

我们会发现项目的src目录下多出了一个 ngsw-config.json 文件,该文件用于定义pwa要缓存的信息,我们可以根据项目的需要进行修改,详细信息可参见angular官网 Service Worker 配置

我们这个demo暂时只配置房型列表的api信息,在 ngsw-config.json 文件中添加内容如下:

...
"dataGroups": [
    {
        "name": "api-rooms",
        "urls": ["/rooms"],
        "cacheConfig" : {
          "maxSize": 100,
          "maxAge": "5d"
      }
  }],
...

表示对后端api中的rooms路径的请求进行缓存

3、重新构建项目

$ ng build --prod

构建完成后,会在dist目录下多出一个对应项目名的文件夹

4、安装独立的 HTTP 服务器
由于 ng serve 对 Service Worker 无效,所以必须用一个独立的 HTTP 服务器在本地测试我们的项目。 我们可以使用任何 HTTP 服务器,本例使用http-server

先安装http-server

$ npm install -g http-server

5、启动HTTP 服务

$ http-server -p 8080 -c-1 dist/gotham-hotel

6、访问 http://127.0.0.1:8080 如果没问题的话,首页和房型列表页都会正常展示。

7、按照上一节的步骤模拟断线,返回到首页,刷新浏览器,再进入列表页,会发现房型列表可以正常展示。


至此,PWA在无连接状态下的可用性就初步展现出来了。同时可以看到,angular在PWA方面也是非常方便的!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容