自 2008 年首次发布以来,使用混合框架进行移动应用程序开发已经走过了漫长的道路。随着 JavaScript 引擎的改进和手机可用处理能力的提高,人们在考虑使用混合框架开发应用程序时的主要担忧混合方法(即性能)几乎已被淘汰,跨平台框架的受欢迎程度激增。
我们将构建一个从Marvel Comics API中提取数据的移动应用程序;数据将显示漫威漫画,您将能够选择您的最爱。最后,我们将在 Android 上创建项目的原生构建。
Ionic Framework是一个开源 UI 工具包,用于使用 Web 技术构建快速、高质量的应用程序,并集成了 Angular 和 React 等流行框架。Ionic 支持使用 Cordova 或 Capacitor 进行跨平台开发,后者支持使用 Electron 进行桌面应用程序开发。
在本文中,我们将通过使用Marvel Comics API构建一个显示漫画的应用程序来探索 Ionic 与 React 的集成,并允许用户创建他们喜欢的集合。我们还将学习如何使用 Capacitor 将原生功能集成到我们的应用程序中,并为原生平台生成构建。
如果您过去没有使用过 Ionic,或者您想了解 Ionic 如何与 React 一起使用,那么本教程适合您。
先决条件
在开始使用 Ionic 框架构建应用程序之前,您将需要以下内容:
- 安装在您的计算机上的 Node.js(至少 v10)
- React的工作知识
- 熟悉 Hooks API
- 一些使用 TypeScript 的经验
- 原生 IDE、适用于 Android 的Android Studio或适用于 iOS的XCode
- 带有 API 密钥的 Marvel 开发者帐户。你可以在这里得到一个
这是我们将要构建的图片:

安装 Ionic CLI
Ionic 应用程序主要通过 Ionic 命令行界面 (CLI) 创建和开发。在您开发混合应用程序时,CLI 提供了广泛的开发工具和帮助选项。要继续阅读本指南,您需要确保 CLI 已安装并可从您的终端访问。
打开一个新的终端窗口并运行以下命令:
npm install -g @ionic/cli
这将安装最新版本的 Ionic CLI 并使其可以从您计算机上的任何位置访问。如果要确认安装是否成功,可以运行以下命令:
ionic --version
此命令将在您的计算机上输出已安装的 Ionic 版本,它应该类似于:
6.4.1
您现在可以使用任何可用的预构建模板为官方支持的框架集成(Angular 和 React)引导 Ionic 应用程序。
启动 Ionic React 应用程序
使用 CLI 创建 Ionic React 应用程序很容易。它提供了一个名为的命令,该命令start
根据您选择的 JavaScript 框架为新项目生成文件。您还可以选择从预构建的 UI 模板开始,而不是默认的空白“Hello world”应用程序。
要开始,请运行以下命令:
ionic start marvel-client tabs --type=react --capacitor
tabs
此命令将使用模板创建一个新的 Ionic React 应用程序。它还向您的应用程序添加了电容器集成。Capacitor 是一个跨平台的应用程序运行时,它使在 iOS、Android 和桌面上本地运行 Web 应用程序变得容易。
将您的终端导航到新创建的目录并运行启动服务器。
cd marvel-client
ionic serve
现在将您的浏览器指向您https://localhost:8100
的应用程序正在运行。
注意:如果你之前用过create-react-app
(CRA),你当前项目的目录结构应该会很熟悉。这是因为,为了保持熟悉的开发体验,Ionic React 项目是使用类似于 CRA 应用程序中的设置创建的。React Router 还用于在后台为应用程序导航提供动力。
创建一个 React 组件
在此步骤中,您将创建一个可重用的 React 组件。该组件将接收数据并显示有关漫画的信息。这一步还旨在帮助证明 Ionic React 仍然只是 React。
从目录中的文件中删除ExploreContainer 组件的文件src/components
并删除其导入。.tsx``src/pages
import React from 'react';
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
在您的Tab1.tsx
文件中,还要删除<IonContent></IonContent>
标签中的内容。
ComicCard.tsx
接下来,在您的目录中创建一个名为的文件src/components
。然后,在编辑器中打开文件并添加以下内容:
import React, { FC } from 'react';
import { Comic } from '../interfaces/comic';
import { IonImg, IonCard, IonCardTitle, IonCardSubtitle, IonCardHeader } from '@ionic/react';
type Props = {
comic: Comic;
}
const ComicCard: FC = (props): JSX.Element => {
const { comic } = props;
return (
<IonCard>
<div
style={{
height: '250px',
overflow: 'hidden',
}}
>
<IonImg
src={`${comic.thumbnail.path}.${comic.thumbnail.extension}`}
/>
</div>
<IonCardHeader>
<IonCardSubtitle>
{comic.title}
</IonCardSubtitle>
<IonCardTitle>
<h3>
{comic.series.name}
</h3>
</IonCardTitle>
</IonCardHeader>
</IonCard>
);
}
export default ComicCard;
您的ComicCard
组件接收包含漫画详细信息的道具并使用IonCard
组件呈现信息。Ionic 中的卡片通常由其他子组件组成。在此文件中,您使用IonCardTitle
和IonCardSubtitle
组件在组件中呈现漫画标题和系列信息IonCardHeader
。
使用 Marvel API
要使用新创建的组件,您必须从 Marvel API 获取一些数据。出于本指南的目的,您将使用axios包来发出 HTTP 请求。您可以通过运行以下命令来安装它:
yarn add axios
接下来,将以下文件夹添加到您的src
目录:
# ~/Desktop/marvel-client/src
mkdir -p services
然后,cd
进入services
目录并创建一个名为api.ts
:
# ~/Desktop/marvel-client/src/services
touch api.ts
最后,打开文件并添加以下内容:
import axios from 'axios';
import { DataContainer } from '../interfaces/data-container';
import { Comic } from '../interfaces/comic';
const API_KEY = '813xxxxxxxxxxxxxxxxxx';
const api = axios.create({
baseURL: 'https://gateway.marvel.com:443/v1/public',
headers: {
'Content-Type': 'application/json',
},
});
api.interceptors.response.use((response) => {
if (response.status === 200) {
return response.data.data;
}
});
export function getComics(): Promise<DataContainer<Comic>> {
return api.get('/comics', {
params: {
apikey: API_KEY,
limit: 10,
hasDigitalIssue: true,
},
});
}
请务必将 的值替换为API_KEY
您自己的 API 密钥。如果您没有,您可以通过在Marvel 开发者网站上注册来申请。您还需要通过添加到您的 Marvel 授权推荐人列表来设置您的帐户以允许来自本地开发服务器的请求localhost*
(见下图):

您现在有一个配置为使用 Marvel API 的 axios 实例。该api.ts文件只有一个导出,它到达GET /comics端点并返回一组漫画。您将结果限制为仅以数字形式提供的结果。您现在将继续在您的应用程序中使用 API 服务。
打开Tab1.tsx文件并将内容替换为以下内容:
import React, { FC, useState, useEffect } from 'react';
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonSpinner, IonGrid, IonRow, IonCol } from '@ionic/react';
import './Tab1.css';
import ComicCard from '../components/ComicCard';
import { Comic } from '../interfaces/comic';
import { getComics } from '../services/api';
const Tab1: FC = () => {
const [comics, setComics] = useState(null as Comic[] | null);
const [loading, setLoading] = useState(false);
const fetchComics = () => {
setLoading(true);
getComics().then((response) => {
if (response && response.results) {
setComics(response.results);
}
}).finally(() => {
setLoading(false);
});
};
useEffect(() => {
fetchComics();
}, [])
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Home</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
{(loading) && (
<div className="ion-text-center ion-padding">
<IonSpinner name="crescent" />
</div>
)}
{(comics) && (
<IonGrid>
<IonRow>
{comics.map((comic) => (
<IonCol key={comic.id} sizeXs="12" sizeSm="6" sizeMd="4" sizeLg="3" sizeXl="2">
<ComicCard comic={comic} />
</IonCol>
))}
</IonRow>
</IonGrid>
)}
</IonContent>
</IonPage>
);
};
export default Tab1;
上面的文件是Ionic中的一个页面示例。页面是可以通过路由/URL 访问的组件。为了确保页面之间的转换正常工作,有必要让IonPage组件成为页面中的根组件。
IonHeader是一个存在于页面顶部的组件。并非所有页面都需要它,但它可以包含有用的组件,例如页面标题、IonBackButton用于在页面之间导航的组件或IonSearchBar. IonContent是页面的主要内容区域。它负责提供用户将与之交互的可滚动内容,以及可在您的应用中使用的任何滚动事件。
在你的组件内部,你有一个名为的函数fetchComics()——在钩子中调用一次useEffect()——它通过调用getComics()你之前编写的函数来请求从 Marvel API 获取漫画。useState()它通过钩子将结果保存到组件的状态中。IonSpinner当您的应用程序向 API 发出请求时,该组件会呈现一个旋转图标。请求完成后,您将结果传递给ComicCard您之前创建的组件。
此时您的应用程序应如下所示:

在下一步中,您将学习如何通过启用离线存储在您的应用程序中使用电容器插件。
创建漫威漫画的个人收藏
到目前为止,您的应用程序看起来不错,但作为移动应用程序并不是很有用。在此步骤中,您将通过允许用户为漫画“加注星标”或将其保存为收藏来扩展应用程序的功能。您还将使用电容器存储插件使有关已保存收藏夹的信息可用于离线查看。

util.ts
首先,在您的目录中创建一个名为的文件src
:
# ~/Desktop/marvel-client/src
touch util.ts
现在,打开文件并粘贴以下内容:
import { Plugins } from '@capacitor/core';
import { Comic } from './interfaces/comic';
const { Storage, Toast } = Plugins;
export const updateFavourites = async (comic: Comic): Promise => {
const saved = await Storage.get({ key: 'savedFavourites' });
const favourites: Comic[] | null = (saved && saved.value)
? JSON.parse(saved.value)
: null;
if (!favourites) {
const comics = [comic];
await Storage.set({
key: 'savedFavourites',
value: JSON.stringify(comics),
});
return Toast.show({
text: 'Added to favourites',
});
}
const copyOfFavourites = favourites.slice();
const { id } = comic;
const isSavedIndex = copyOfFavourites.findIndex((c) => c.id === id);
if (isSavedIndex !== -1) {
copyOfFavourites.splice(isSavedIndex, 1);
await Storage.set({
key: 'savedFavourites',
value: JSON.stringify(copyOfFavourites),
});
return Toast.show({
text: 'Removed from favourites',
});
} else {
copyOfFavourites.unshift(comic);
await Storage.set({
key: 'savedFavourites',
value: JSON.stringify(copyOfFavourites),
});
return Toast.show({
text: 'Added to favourites',
});
}
};
export const getFavourites = async (): Promise<Comic[] | null> => {
const saved = await Storage.get({
key: 'savedFavourites',
});
return (saved && saved.value)
? JSON.parse(saved.value)
: null;
};
export const checkFavourite = async (id: number): Promise<boolean> => {
const saved = await Storage.get({
key: 'savedFavourites',
});
const favourites: Comic[] | null = (saved && saved.value)
? JSON.parse(saved.value)
: null;
if (favourites) {
const isSavedIndex = favourites.findIndex((c) => c.id === id);
if (isSavedIndex !== -1) {
return true;
}
}
return false;
};
Storage 插件为简单数据提供键值存储,而 Toast 插件提供通知弹出窗口,用于向用户显示重要信息。
此文件中的updateFavourites()
函数采用单个参数,一个Comic
对象,如果它不存在,则将其添加到设备存储中,如果已保存,则将其从设备存储中删除。getFavourites()
返回用户保存的漫画,同时checkFavourites()
接受一个参数,一个Comic
资源 ID,并在保存的漫画中查找,true
如果存在则返回,false
否则返回。
接下来,打开ComicCard.tsx
文件并进行以下更改,以允许您的应用程序的用户保存他们喜欢的漫画:
import { star, starOutline } from 'ionicons/icons';
import * as utils from '../util';
您的ComicCard
组件现在有一个IonButton
组件,当单击该组件时,它会调用updateFavourites()
您之前编写的函数。请记住,该功能就像一个切换,如果漫画已经保存,则删除它,否则保存它。不要忘记为新的 Ionic 组件添加导入IonButton
,IonCardContent
和IonIcon
,刚刚添加到该组件中。
现在是这一步的最后一部分,您将在他们自己的页面中渲染保存的漫画。将Tab2.tsx
文件的内容替换为以下内容:
import React, { useState } from 'react';
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonGrid, IonRow, IonCol, useIonViewWillEnter } from '@ionic/react';
import './Tab2.css';
import { Comic } from '../interfaces/comic';
import { getFavourites } from '../util';
import ComicCard from '../components/ComicCard';
const Tab2: React.FC = () => {
const [comics, setComics] = useState(null as Comic[] | null);
const loadComics = (): void => {
getFavourites().then((result) => {
if (result) {
setComics(result);
}
})
};
useIonViewWillEnter(() => {
loadComics();
});
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Favourites</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
{(comics) && (
<IonGrid>
<IonRow>
{comics.map((comic) => (
<IonCol key={comic.id} sizeXs="12" sizeSm="6" sizeMd="4" sizeLg="3" sizeXl="2">
<ComicCard comic={comic} />
</IonCol>
))}
</IonRow>
</IonGrid>
)}
</IonContent>
</IonPage>
);
};
export default Tab2;
此页面与该页面非常相似,Tab1
但您访问的是本地保存的数据,而不是发出 API 请求来获取漫画。您还使用 Ionic 生命周期挂钩,useIonViewWillEnter()
而不是useEffect()
挂钩,来调用读取保存的漫画并更新组件状态的函数。钩子在useIonViewWillEnter()
被导航到的页面进入视图时被调用。
您的应用程序现在使用一些本机插件来改进其功能。在下一步中,您将学习如何为 Android 生成原生项目并使用 Android Studio 创建原生应用。
注意:您可以删除文件中相关的文件 *Tab3*
和删除文件中的导入和相关 *IonTab*
组件 *App.tsx*
。
生成原生项目
Ionic 支持跨平台应用程序运行时,例如 Capacitor 和 Cordova。这些框架可帮助您在本机设备或模拟器上构建和运行使用 Ionic 开发的应用程序。出于本指南的目的,您将使用 Capacitor 生成本机项目文件。
在继续添加平台之前,您需要生成应用程序的生产版本。在项目的根目录中运行以下命令来执行此操作:
ionic build
现在让我们将 Capacitor 添加到您的项目中并生成构建本机应用程序所需的资产。Capacitor 提供了一个 CLI,可以通过使用npx
或从ionic
CLI 在您的项目中访问,如下所示:
使用npx
npx cap add android
此命令将android
平台添加到您的项目中。其他可能的平台值是ios
和electron
。
使用ionic
由于您--capacitor
之前使用该标志初始化了您的项目,因此 Capacitor 已经使用您的项目信息进行了初始化。您可以通过运行以下命令继续添加平台:
ionic capacitor add android
此命令将为android
平台安装所需的依赖项。它还将生成原生 Android 项目所需的文件,并在运行时复制您之前构建的资产ionic build
。
如果您已经安装了 Android Studio,您现在可以通过运行以下命令在 Android Studio 中打开您的项目:
ionic capacitor open android
最后,构建您的项目:

结论
在本指南中,您学习了如何使用 Ionic Framework 的 React 集成开发混合移动应用程序。您还学习了如何使用 Capacitor 构建本机应用程序,特别是针对 Android 平台。查看 API 文档,因为有更多 UI 组件可用于我们未探索的 Ionic 应用程序。
链接:https://www.smashingmagazine.com/2020/05/introduction-react-ionic/
网友评论