Skip to main content

用相机拍照

¥Taking Photos with the Camera

现在是有趣的部分 - 添加使用 Capacitor 相机接口 使用设备相机拍照的功能。我们将从为网络构建它开始,然后进行一些小调整以使其在移动设备(iOS 和 Android)上运行。

¥Now for the fun part - adding the ability to take photos with the device’s camera using the Capacitor Camera API. We’ll begin with building it for the web, then make some small tweaks to make it work on mobile (iOS and Android).

为此,我们将创建一个独立的合成函数,与 Vue 的合成 API 配合使用来管理图库的照片。

¥To do so, we will create a standalone composition function paired with Vue's Composition API to manage the photos for the gallery.

注意

如果你不熟悉 Vue 的 Composition API,Vue 官方文档中的 为什么选择组合 API? 是一个很好的入门资源。

¥If you are not familiar with Vue's Composition API, Why Composition API? from the official Vue docs is a good resource to start with.

src/composables/usePhotoGallery.ts 创建一个新文件并打开它。

¥Create a new file at src/composables/usePhotoGallery.ts and open it up.

我们将首先从 Vue core 和 Capacitor 导入我们将使用的各种实用程序:

¥We will start by importing the various utilities we will use from Vue core and Capacitor:

import { ref, onMounted, watch } from 'vue';


import { Camera, CameraResultType, CameraSource, Photo } from '@capacitor/camera';




import { Filesystem, Directory } from '@capacitor/filesystem';




import { Preferences } from '@capacitor/preferences';


接下来,创建一个名为 usePhotoGallery 的函数:

¥Next, create a function named usePhotoGallery:

export const usePhotoGallery = () => {
const takePhoto = async () => {
const photo = await Camera.getPhoto({
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
quality: 100,
});
};

return {
takePhoto,
};
};

我们的 usePhotoGallery 函数公开了一个名为 takePhoto 的方法,该方法又调用 Capacitor Camera API 的 getPhoto 方法。

¥Our usePhotoGallery function exposes a method called takePhoto, which in turn calls the Capacitor Camera API's getPhoto method.

注意这里的魔力:没有特定于平台的代码(Web、iOS 或 Android)!Capacitor Camera 插件为我们抽象了这一点,只留下一个方法调用 - getPhoto() - 这将打开设备的相机并允许我们拍照。

¥Notice the magic here: there's no platform-specific code (web, iOS, or Android)! The Capacitor Camera plugin abstracts that away for us, leaving just one method call - getPhoto() - that will open up the device's camera and allow us to take photos.

我们需要执行的最后一步是使用 Tab2 页面中的新功能。返回 Tab2Page.vue 并导入:

¥The last step we need to take is to use the new function from the Tab2 page. Go back to Tab2Page.vue and import it:



import { usePhotoGallery } from '@/composables/usePhotoGallery';


usePhotoGallery 解构 takePhoto 函数,以便我们可以在 template 中使用它:

¥Destructure the takePhoto function from usePhotoGallery so we can use it in our template:

<script setup lang="ts">
import {
IonContent,
IonCol,
IonFab,
IonFabButton,
IonGrid,
IonPage,
IonHeader,
IonIcon,
IonImg,
IonRow,
IonTitle,
IonToolbar,
} from '@ionic/vue';
import { camera, trash, close } from 'ionicons/icons';


import { usePhotoGallery } from '@/composables/usePhotoGallery';



const { takePhoto } = usePhotoGallery();
</script>

保存文件。如果开发服务器尚未运行,请通过 ionic serve 启动它。在浏览器的“照片库”选项卡上,单击“相机”按钮。如果你的计算机有任何类型的网络摄像头,则会出现一个模式窗口。来张自拍照吧!

¥Save the file. Start the development server via ionic serve if it is not already running. In your browser, on the Photo Gallery tab, click the Camera button. If your computer has a webcam of any sort, a modal window appears. Take a selfie!

A photo gallery app displaying a webcam selfie.

(你的自拍可能比我的好得多)

¥*(Your selfie is probably much better than mine)*

拍完照片后,它立即消失。我们仍然需要在我们的应用中显示它并保存它以供将来访问。

¥After taking a photo, it disappears right away. We still need to display it within our app and save it for future access.

显示照片

¥Displaying Photos

首先,我们将创建一个新类型来定义我们的照片,它将保存特定的元数据。将以下 UserPhoto 接口添加到 usePhotoGallery.ts 文件中主函数之外的某个位置:

¥First we will create a new type to define our Photo, which will hold specific metadata. Add the following UserPhoto interface to the usePhotoGallery.ts file, somewhere outside of the main function:

export interface UserPhoto {
filepath: string;
webviewPath?: string;
}

usePhotoGallery 函数的顶部,定义一个数组,以便我们可以存储用相机拍摄的每张照片。使用 Vue 的 参考函数 将其设为响应式变量。

¥At the top of the usePhotoGallery function, define an array so we can store each photo captured with the Camera. Make it a reactive variable using Vue's ref function.

const photos = ref<UserPhoto[]>([]);

当相机完成拍照后,从 Capacitor 返回的结果 Photo 将被添加到 photos 数组中。更新 takePhoto 函数,在 Camera.getPhoto 行后添加以下代码:

¥When the camera is done taking a picture, the resulting Photo returned from Capacitor will be added to the photos array. Update the takePhoto function, adding this code after the Camera.getPhoto line:

const fileName = Date.now() + '.jpeg';
const savedFileImage = {
filepath: fileName,
webviewPath: photo.webPath,
};

photos.value = [savedFileImage, ...photos.value];

接下来,更新 return 语句以包含照片数组:

¥Next, update the return statement to include the photos array:

return {
photos,
takePhoto,
};

返回 Tab2 组件,更新导入语句以包含 UserPhoto 接口:

¥Back in the Tab2 component, update the import statement to include the UserPhoto interface:



import { usePhotoGallery, UserPhoto } from '@/composables/usePhotoGallery';


然后,访问照片数组:

¥Then, get access to the photos array:

const { photos, takePhoto } = usePhotoGallery();

将照片存储到主数组后,我们现在可以在屏幕上显示图片。添加 网格组件,以便每张照片在添加到图库时都能很好地显示,并循环遍历照片数组中的每张照片,为每张照片添加一个图片组件 (<ion-img>)。将 src(源)指向照片的路径:

¥With the photo(s) stored into the main array we can now display the images on the screen. Add a Grid component so that each photo will display nicely as they are added to the gallery, and loop through each photo in the Photos array, adding an Image component (<ion-img>) for each. Point the src (source) to the photo's path:

<ion-content>
<ion-grid>
<ion-row>
<ion-col size="6" :key="photo.filepath" v-for="photo in photos">
<ion-img :src="photo.webviewPath"></ion-img>
</ion-col>
</ion-row>
</ion-grid>

<!-- <ion-fab> markup -->
</ion-content>

保存所有文件。在网络浏览器中,单击相机按钮并拍摄另一张照片。这次,照片显示在照片库中!

¥Save all files. Within the web browser, click the Camera button and take another photo. This time, the photo is displayed in the Photo Gallery!

接下来,我们将添加对将照片保存到文件系统的支持,以便稍后可以在我们的应用中检索和显示它们。

¥Up next, we’ll add support for saving the photos to the filesystem, so they can be retrieved and displayed in our app at a later time.