如何在Angular 9中构建渐进式网络应用程序(PWA)

如何在Angular 9中构建渐进式网络应用程序(PWA)

在这篇文章中,我们将使用Angular开发一个PWA(渐进式网络应用程序)。

什么是PWA?

渐进式网络应用程序(PWA)是网络应用程序,其设计使其具有能力、可靠性和可安装性。PWA是用现代API构建和增强的,以提供增强的功能、可靠性和可安装性,同时又能在任何地方、任何设备上用单一代码库接触到任何人。PWA不需要通过应用商店进行部署;相反,我们使用不同的方法,通过URL在网络服务器上进行部署。但在开发PWA时,我们必须注意以下因素。

1.响应性。在每一个设备上工作,如桌面、手机或平板电脑,没有任何破损。
2.2.安全和保障。 使用HTTPS为我们的PWA提供数据,确保安全。
3.渐进式。使用现代网络功能,为每个用户开发类似应用程序的体验。
4.自动更新。下载和安装更新,无需用户干预。(这是在服务工作者的帮助下进行的)。
5.可发现。PWA应该是可以通过搜索引擎搜索的。(使用网络应用程序清单)
6.可安装。可安装在用户的设备主屏幕上。
7.离线工作。它应该为离线工作和在稀疏的网络上配置。

第1步:初始化新的Angular项目:现在,首先让我们开始创建一个Angular应用程序。在这里,我们将创建一个简单的天气应用程序。要做到这一点,首先,创建一个新的Angular应用程序,并使用以下命令导航到项目目录内。

ng new weather-app
cd weather-app

第2步:添加Bootstrap链接:在开发前端时,我们将使用Bootstrap进行样式设计。在你的项目的index.html文件中添加以下链接。

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6″ crossorigin="anonymous">
<script src=”https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js” integrity=”sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf” crossorigin=”anonymous”></script>

第3步:OpenWeatherMap API获取天气数据:为了获取天气的实时数据,我们将使用openweathemap API。通过创建您的账户获得一个API密钥。

第4步:为WeatherApp开发用户界面:通过运行以下命令创建一个名为weather的angular组件和名为API的angular服务。

ng generate component components/weather
ng generate service services/API

现在,将以下代码粘贴到各自的文件中。

import { Component, OnInit } from '@angular/core';
import { WeatherService }
     from 'src/app/services/weather.service';
  
@Component({
  selector: 'app-weather',
  templateUrl: './weather.component.html',
  styleUrls: ['./weather.component.css'],
})
export class WeatherComponent implements OnInit {
  city: any = '';
  country: any = '';
  weather: any = null;
  
  constructor(private
   _weatherService: WeatherService) {}
  
  ngOnInit(): void {}
  
  getDate(str: string) {
    return str.split(' ')[0];
  }
  
  getTime(str: string) {
    return str.split(' ')[1];
  }
  
  displayWeather() {
    this._weatherService
  .getWeather(this.city, this.country)
  .subscribe(
      (data) => (this.weather = data),
      (err) => console.log(err)
    );
  }
}
<div class="container-fluid">
  <div class="input card">
    <div class="mb-4">
      <label for="city" class="form-label">
        City<span class="text-danger">*
        </span>
      </label>
      <input type="text" class="form-control" 
             name="city" id="city" [(ngModel)]="city"/>
    </div>
    <div class="mb-1">
      <label for="country" class="form-label">
        Country<span class="text-danger">*
        </span></label>
      <input type="text" class="form-control"
             name="country" id="country" 
             [(ngModel)]="country"/>
    </div>
    <div class="text-center mt-4">
      <button type="submit" class="btn btn-primary" 
              (click)="displayWeather()">
        Get Weather</button>
    </div>
  </div>
  
  <div class="row" *ngIf="weather" 
       [(ngModel)]="weather">
    <div class="col-md-3" *ngFor="let wth of weather.list">
      <div class="weather-info">
        <div class="d-flex justify-content-between">
          <div class="info-date">
            <h1>{{ wth.dt_txt | date: "shortTime" }}</h1>
            <span>{{ getDate(wth.dt_txt) | date }}</span>
            <span class="weather-city">{{ city }},
              {{ country }}</span>
          </div>
  
          <div class="info-weather">
            <div class="weather-wrapper">
              <span class="weather-temperature">
                {{ wth.main.temp - 273.15 | number: "1.1-1" }}°C
              </span>
              <div class="weather-type">
                <img src=
   "https://openweathermap.org/img/wn/{{wth.weather[0].icon}}@2x.png"
                  width="64px" height="64px" 
                     alt="Weather Icon"/>
              </div>
              <br />
            </div>
            <span class="weather-description">
              {{ wth.weather[0].description | titlecase }}
            </span>
          </div>
        </div>
        <div class="d-flex justify-content-between mt-3">
          <div class="humidity"><img src="" alt=""> 
            Humidity {{ wth.main.humidity }}%</div>
          <div class="wind">
            <i class="fas fa-wind"></i>Wind 
            {{ wth.wind.speed }} km/h
          </div>
          <div class="pressure">Pressure 
            {{ wth.main.pressure }}</div>
        </div>
      </div>
    </div>
  </div>
</div>
.col-md-3 {
  margin: 5px auto;
}
  
.input {
  margin: 2% 25%;
  padding: 2% 2.5%;
  font-size: 16px;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
  transition: 0.3s;
}
  
input {
  padding: 10px 12px;
}
  
.weather-info {
  width: 100%;
  height: 100%;
  padding: 20px 20px;
  border-radius: 8px;
  border: 2px solid #fff;
  box-shadow: 0 0 4px rgba(255, 255, 255, 0.3);
  background: linear-gradient(to right, #00a4ff, #0072ff);
  transition: transform 0.2s ease;
  color: whitesmoke;
}
  
.info-date {
  display: flex;
  flex-direction: column;
  justify-content: center;
}
  
.info-date h1 {
  margin-bottom: 0.65rem;
  font-size: 2rem;
  letter-spacing: 2px;
}
  
.info-weather {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  text-align: right;
}
  
.weather-wrapper {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  width: 100%;
}
@keyframes animation-icon {
  from {
    transform: scale(1);
  }
  to {
    transform: scale(1.2);
  }
}
  
.weather-type {
  display: inline-block;
  width: 48px;
  height: 48px;
  transition: all 0.2s ease-in;
  animation: animation-icon 0.8s infinite;
  animation-timing-function: linear;
  animation-direction: alternate;
}
.weather-temperature {
  font-size: 1.5rem;
  font-weight: 800;
}
  
.weather-description {
  margin-top: 1rem;
  font-size: 20px;
  font-weight: bold;
}
  
.weather-city {
  margin-top: 0.25rem;
  font-size: 16px;
}
  
.wind i {
  margin: 10px;
}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
  
@Injectable({
  providedIn: 'root',
})
export class WeatherService {
  private readonly apiKey: string = <your API key>;
  
  constructor(private _http: HttpClient) {}
  
  getWeather(city: string, country: string) {
    const apiUrl = 
 `https://api.openweathermap.org/data/2.5/forecast?q={city},{country}&appid=${this.apiKey}`;
    return this._http.get(apiUrl);
  }
}

现在在app.component.html中调用天气组件

<app-weather></app-weather>

输出:

如何在Angular 9中构建渐进式网络应用程序(PWA)?

第5步:将Angular应用程序转换为PWA:使用Angular CLI将你的Angular应用程序转换为PWA很容易。导航到你的项目的文件夹。现在,运行以下命令来添加PWA功能。

ng add @angular/pwa

上述命令添加了以下新文件。

  1. 命名为manifest.webmanifest的PWA信息文件

  2. 用于配置服务工作者的ngsw-config.json文件

  3. 在assets/icons目录下有许多尺寸的默认图标(这些图标以后可以改变)。
  4. 使用@angular/service-worker软件包的服务工作者

现在,让我们看一下每个文件的作用。

manifest.webmanifest

这个文件包含应用程序的名称、主题和背景颜色,以及各种尺寸的图标。当你把应用程序添加到移动端时,这个配置就会被应用,它通过把名称和图标添加到应用程序列表中来创建一个网络视图,当应用程序运行时,背景和主题颜色就会被应用。

{
  "name": "weather-app",
  "short_name": "weather-app",
  "theme_color": "#1976d2",
  "background_color": "#fafafa",
  "display": "standalone",
  "scope": "./",
  "start_url": "./",
  "icons": [
    {
      "src": "assets/icons/icon-72x72.png",
      "sizes": "72x72",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "assets/icons/icon-96x96.png",
      "sizes": "96x96",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "assets/icons/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "assets/icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "assets/icons/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "assets/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "assets/icons/icon-384x384.png",
      "sizes": "384x384",
      "type": "image/png",
      "purpose": "maskable any"
    },
    {
      "src": "assets/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable any"
    }
  ]
}

ngsw-config 这个文件的存在,人们将能够管理与PWA相关的各种不同的东西。这就是我们缓存API端点的地方。

{
 "$schema": "./node_modules/@angular/service-worker/config/schema.json",
 "index": "/index.html",
 "assetGroups": [
   {
     "name": "app",
     "installMode": "prefetch",
     "resources": {
       "files": [
         "/favicon.ico",
         "/index.html",
         "/manifest.webmanifest",
         "/*.css",
         "/*.js"
       ]
     }
   },
   {
     "name": "assets",
     "installMode": "lazy",
     "updateMode": "prefetch",
     "resources": {
       "files": [
         "/assets/**",
         "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
       ]
     }
   }
 ]
}

第6步:为生产环境建立我们的Angular App:

ng build --prod

运行上述命令后,我们的build文件夹在dist/weather-app中被创建。现在,用cd dist/weather-app移动到构建文件夹中。

cd dist/weather-app

使用NPM全局安装http-server包。

npm install -g http-server

你可以在这里找到这个天气应用程序的代码。

第7步:在桌面上添加我们的天气应用程序图标来启动:一旦你将在浏览器中启动angular应用程序,在URL栏的右侧会出现一个下载图标,如下所示。

如何在Angular 9中构建渐进式网络应用程序(PWA)?

安装天气应用程序

点击 “安装 “按钮,在桌面上添加图标以启动该应用程序。现在,你点击在桌面上创建的应用程序图标。你会看到以下屏幕。(注意:当你点击该图标时,它不会在浏览器中打开。)

如何在Angular 9中构建渐进式网络应用程序(PWA)?

从桌面(任何设备)启动应用程序

卸载PWA很容易。只要点击顶部导航中的三个点,然后点击 “卸载天气应用程序”。

如何在Angular 9中构建渐进式网络应用程序(PWA)?

Uninstalling PWA

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程