📌  相关文章
📜  如何在 Angular 9 中构建渐进式 Web 应用程序(PWA)?

📅  最后修改于: 2022-05-13 01:56:41.796000             🧑  作者: Mango

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

在本文中,我们将使用 Angular 开发一个 PWA(Progressive Web App)。

什么是 PWA?

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

  1. 响应能力:适用于台式机、移动设备或平板电脑等所有设备,不会出现任何损坏。
  2. 安全且安全:使用 HTTPS 向我们的 PWA 提供数据可确保安全性。
  3. 渐进式:使用现代网络功能为每个用户开发类似应用程序的体验。
  4. 自动更新:无需用户干预即可下载和安装更新。 (这是在 Service Worker 的帮助下)
  5. 发现: PWA 应该可以通过搜索引擎进行搜索。 (使用网络应用清单)
  6. 可安装:可安装在用户的设备主屏幕上。
  7. 离线工作:它应该配置为离线工作和稀疏网络。

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

ng new weather-app
cd weather-app

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

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

第 4 步:为 WeatherApp 开发 UI:通过运行以下命令创建一个名为weather的 Angular 组件和名为API的 Angular 服务:

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

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

weather.component.ts
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)
    );
  }
}


weather.component.html
  
    
                  
    
                  
    
           
  
     
    
      
        
          
            

{{ wth.dt_txt | date: "shortTime" }}

            {{ getDate(wth.dt_txt) | date }}             {{ city }},               {{ country }}           
             
            
                               {{ wth.main.temp - 273.15 | number: "1.1-1" }}°C                              
                               
              
            
                           {{ wth.weather[0].description | titlecase }}                        
        
        
          
              Humidity {{ wth.main.humidity }}%
          
            Wind              {{ wth.wind.speed }} km/h           
          
Pressure              {{ wth.main.pressure }}
        
      
    
  


weather.component.css
.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;
}


weather.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
  
@Injectable({
  providedIn: 'root',
})
export class WeatherService {
  private readonly apiKey: string = ;
  
  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);
  }
}


Javascript
{
  "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"
    }
  ]
}


Javascript
{
 "$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)"
       ]
     }
   }
 ]
}


天气.component.html

  
    
                  
    
                  
    
           
  
     
    
      
        
          
            

{{ wth.dt_txt | date: "shortTime" }}

            {{ getDate(wth.dt_txt) | date }}             {{ city }},               {{ country }}           
             
            
                               {{ wth.main.temp - 273.15 | number: "1.1-1" }}°C                              
                               
              
            
                           {{ wth.weather[0].description | titlecase }}                        
        
        
          
              Humidity {{ wth.main.humidity }}%
          
            Wind              {{ wth.wind.speed }} km/h           
          
Pressure              {{ wth.main.pressure }}
        
      
    
  

天气.component.css

.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;
}

天气服务.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
  
@Injectable({
  providedIn: 'root',
})
export class WeatherService {
  private readonly apiKey: string = ;
  
  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中的天气组件

输出:

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

ng add @angular/pwa

上面的命令添加了以下新文件:

  1. 用于 PWA 信息的名为 manifest.webmanifest 的清单文件
  2. 用于配置 service worker 的 ngsw-config.json 文件
  3. assets/icons 目录中具有多种尺寸的默认图标(这些图标可以稍后更改)
  4. 使用 @angular/service-worker 包的服务工作者

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

manifest.webmanifest

该文件包含应用程序的名称、主题和背景颜色,以及各种大小的图标。当您将应用程序添加到移动设备时应用此配置,它通过将名称和图标添加到应用程序列表来创建 Web 视图,并且当应用程序运行时应用背景和主题颜色。

Javascript

{
  "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 端点的地方。

Javascript

{
 "$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 应用程序:

ng build --prod

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

cd dist/weather-app

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

npm install -g http-server

您可以在此处找到此天气应用程序的代码。

第 7 步:在桌面上添加我们的 Weather App 图标以启动:在浏览器中启动 Angular 应用程序后,URL 栏右侧会出现一个下载图标,如下所示:

安装天气应用

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

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

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

卸载 PWA