跳转至正文
教程

使用 Vue 和 Capacitor 构建移动应用

学习如何使用 Vue 和 Capacitor 开发移动应用,并可选了解如何优化 Capgo Native Navigation、过渡动画以及 iOS 布局的最佳实践。

使用 Vue 和 Capacitor 构建移动应用

在本教程中,我们将指导你如何使用 Capacitor 将 Vue Web 应用转换为原生移动应用。你还可以添加 Capgo Native Navigation and Transitions 以获得原生移动体验,并使用 tailwind-capacitor 来处理安全区域。

关于 Capacitor

Capacitor 是一款颠覆性的工具,它可以轻松集成到任何 Web 项目中,并将你的应用转换为原生移动应用。它能为你生成原生的 Xcode 和 Android Studio 项目,并通过 JavaScript bridge 提供对摄像头等原生设备功能的访问。

准备你的 Vue 应用

首先,运行以下命令创建一个新的 Vue 应用:

vue create my-app
cd my-app
npm install

为了让您的 Vue 应用能够进行原生移动端部署,您需要导出项目。请在您的 package.json 文件中添加一个用于构建并复制 Vue 项目的 script:

{
  "scripts": {
    // ...
    "build": "vue-cli-service build"
  }
}

运行完 build 命令后,您应该会在项目根目录下看到一个新的 dist 文件夹。稍后 Capacitor 将会使用该文件夹。

在您的 Vue 应用中添加 Capacitor

要将您的 Vue Web 应用转换为原生移动端容器,请按照以下步骤操作:

  1. 将 Capacitor CLI 作为开发依赖安装,并在项目中完成配置。在设置过程中,请直接使用默认的 name 和 bundle ID。

  2. 安装核心包以及 iOS 和 Android 平台的相关包。

  3. 添加平台后,Capacitor 会在项目根目录下为每个平台创建对应的文件夹:

# Install the Capacitor CLI locally
npm install -D @capacitor/cli

# Initialize Capacitor in your Vue project
npx cap init

# Install the required packages
npm install @capacitor/core @capacitor/ios @capacitor/android

# Add the native platforms
npx cap add ios
npx cap add android

你现在应该能在 Vue 项目中看到新的 iOS 以及 Android 文件夹。

更新 capacitor.config.json 文件,将 webDir 指向你 build 命令的输出目录:

{
  "appId": "com.example.app",
  "appName": "my-app",
  "webDir": "dist"
}

现在,你可以构建 Vue 项目并将其同步到 Capacitor:

npm run build
npx cap sync

构建并部署 Native Apps

开发 iOS 应用需要安装 Xcode,开发 Android 应用则需要安装 Android Studio。此外,若要在应用商店发布应用,您还需要加入 Apple Developer Program (iOS) 和 Google Play Console (Android)。

使用 Capacitor CLI 同时打开两个原生项目:

npx cap open ios
npx cap open android

使用 Android Studio 或 Xcode 将应用部署到已连接的设备上。

Capacitor 热重载

通过让 Capacitor 应用从网络中的特定 URL 加载内容,即可在移动设备上启用 live reload。

找到您的本地 IP 地址并更新 capacitor.config.ts 文件,填入正确的 IP 和端口:

import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'my-app',
  webDir: 'dist',
  bundledWebRuntime: false,
  server: {
    url: 'http://192.168.x.xx:8080',
    cleartext: true
  }
};

export default config;

将这些更改复制到您的原生项目中以生效:

npx cap copy

现在,当您更新 Vue 应用时,您的应用将自动重新加载并显示更改。

使用 Capacitor 插件

安装一个 Capacitor 插件(例如 Share 插件),并在您的 Vue 应用中使用它:

npm i @capacitor/share

导入该 package 并调用 share() 应用中的函数:

<template>
  <div>
    <h1>Welcome to Vue and Capacitor!</h1>
    <button @click="share">Share now!</button>
  </div>
</template>

<script setup lang="ts">
import { Share } from '@capacitor/share';

async function share() {
  await Share.share({
    title: 'Open Youtube',
    text: 'Check new video on youtube',
    url: 'https://www.youtube.com',
    dialogTitle: 'Share with friends'
  });
}
</script>

安装新插件后,请运行 sync 命令并重新部署应用到设备:

npx cap sync

接下来,你可以通过 Capgo 导航和过渡效果,让应用在 iOS 和 Android 上更具原生感,并修复会导致水平溢出或安全区域被裁剪的常见 iOS 布局问题。

使用 Capgo 原生导航与过渡效果,打造原生感 UI

我多年来一直在使用 Ionic 用于构建跨平台应用,但如果你已经有了,将它与 Vue 集成会显得很生硬,且通常不值得这样做。 Tailwind CSS.

若想在 Vue + Capacitor 应用中获得原生移动端体验,请使用 Capgo 插件,而不是 Konsta UI 等仅限 Web 的 UI 组件库:

  • @capgo/capacitor-native-navigation — 原生导航栏、iOS 上的 Liquid Glass 标签栏,以及 Android 上的毛玻璃效果标签栏。你的 Vue router 负责维护路由状态,而插件则负责控制原生 UI 框架。
  • @capgo/capacitor-transitions — 在 WebView 层实现 Ionic 风格的页面过渡和 iOS 边缘侧滑返回,而无需采用 Ionic UI。

安装两者:

bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync

使用 CSS inset 模式配置原生导航,让 Web 内容正确避让原生栏:

import { NativeNavigation } from '@capgo/capacitor-native-navigation';

await NativeNavigation.configure({
  contentInsetMode: 'css',
  animationDuration: 360,
  glass: {
    effect: 'liquidGlass',
  },
});

渲染 Liquid Glass 标签栏(iOS 使用系统原生渲染;Android 使用毛玻璃 WebView 背景):

await NativeNavigation.setTabbar({
  selectedId: 'home',
  labelVisibilityMode: 'labeled',
  icons: true,
  colors: { dynamic: true },
  tabs: [
    { id: 'home', title: 'Home', icon: { svg: '...' } },
    { id: 'settings', title: 'Settings', icon: { svg: '...' } },
  ],
});

await NativeNavigation.addListener('tabSelect', ({ id }) => {
  router.push(`/${id}`);
});

在应用外壳中添加原生页面转场效果:

<script setup>
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import '@capgo/capacitor-transitions';
import { initTransitions, setDirection, setupRouterOutlet } from '@capgo/capacitor-transitions/vue';

initTransitions({ platform: 'auto' });

const router = useRouter();
const outletRef = ref(null);

onMounted(() => {
  if (outletRef.value) {
    setupRouterOutlet(outletRef.value, { platform: 'auto', swipeGesture: 'auto' });
  }
});

const openSettings = () => {
  setDirection('forward');
  router.push('/settings');
};
</script>

<template>
  <cap-router-outlet ref="outletRef">
    <router-view />
  </cap-router-outlet>
</template>

将路由页面包裹在 cap-router-outlet, cap-page,以及 cap-content,并调用 setDirection('forward') 或 setDirection('back') 在跳转前执行。当原生导航已占用这些区域时,请勿重复添加 Web 端页眉或页脚。

查看完整指南: 使用 @capgo/capacitor-native-navigation 以及 使用 @capgo/capacitor-transitions.

使用 Tailwind 处理安全区域

在 Tailwind CSS 中处理设备安全区域,请使用 @capgo/tailwind-capacitor (发布为 tailwind-capacitor 在 npm 上)。它提供 safe-areas 工具类和其他对 Capacitor 友好的 Tailwind 插件:

bun add -D tailwind-capacitor

在 src/assets/main.css:

@import 'tailwindcss';
@plugin "@capgo/tailwind-capacitor/platform";
@plugin "@capgo/tailwind-capacitor/safe-areas";

使用以下工具类,例如 pt-safe, pb-safe,以及 px-safe 而不是零散地 env(safe-area-inset-*) 手动完成。项目正在积极开发中 —— 如果你的 Vue 配置缺少什么, 请在 GitHub 上提交 PR.

修复 iOS 布局问题(视口、安全区域与水平溢出)

如果 iOS 上的内容看起来被裁剪、偏移或可水平滚动,仅靠添加更多 overflow-x: hidden 或单独调整 viewport 标签通常无法解决问题。请按顺序进行以下检查。

确保 viewport meta 标签已正确应用

在……中添加 viewport meta 标签 index.html 内部 <head>:

<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />

只用一个根容器处理 iOS 安全区域

创建一个统一的 app shell,并在其中应用 safe area 内边距,而不是在多个嵌套组件中:

html,
body,
#app {
  width: 100%;
  min-height: 100%;
  margin: 0;
  padding: 0;
  overflow-x: hidden;
}

* {
  box-sizing: border-box;
}

.app-shell {
  min-height: 100dvh;
  width: 100%;
  padding-top: env(safe-area-inset-top);
  padding-right: env(safe-area-inset-right);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
}

将所有页面内容包裹在 .app-shell。在 header、modal 和 layout wrapper 中重复设置 safe-area padding 往往会让 UI 看起来被裁剪或过大。

使用 @capgo/tailwind-capacitor,你可以使用以下工具类来实现相同的内边距: pt-safe pb-safe px-safe 在这个单一 shell 上。

设置 Capacitor iOS contentInset 改为 never 首先

在 capacitor.config.ts,建议禁用 native inset,让 CSS(或 Native Navigation 的 contentInsetMode: 'css')来管理安全区域:

const config: CapacitorConfig = {
  appId: 'com.example.myapp',
  appName: 'my-app',
  webDir: 'dist',
  ios: {
    contentInset: 'never',
  },
};

将 Capacitor 的自动 content inset 与 CSS env(safe-area-inset-*) padding 混合使用,是导致间距翻倍的常见原因。

找到真正溢出的元素

常见原因是某个元素使用了 100vw,Tailwind w-screen,固定像素宽度或较大的 min-width.

在 Safari Web Inspector 中运行:

[...document.querySelectorAll('*')]
  .filter(el => el.scrollWidth > document.documentElement.clientWidth)
  .map(el => ({
    el,
    tag: el.tagName,
    class: el.className,
    scrollWidth: el.scrollWidth,
    clientWidth: document.documentElement.clientWidth,
  }));

使用 Tailwind 时,替换 w-screen 配合 w-full 尽可能避免。许多水平溢出问题源于 100vw / w-screen,重复的安全区域内边距 (safe-area padding) 或固定宽度的容器,而非 viewport meta 标签本身。

总结

对于基于现有 Web 项目构建 Native Build 应用,Capacitor 是一个绝佳选择。配合 Capgo 使用,为应用添加 Live Update 会变得更加简单,确保您的用户始终能体验到最新的功能和修复。

了解 Capgo 如何助您更高效地构建优质应用, 注册免费账号 今天就开始。

延续《使用 Vue 和 Capacitor 构建移动应用》系列教程

如果你正在使用 使用 Vue 和 Capacitor 构建移动应用 来规划原生媒体和界面行为,并将其与 使用 @capgo/capacitor-live-activities 用于使用 @capgo/capacitor-live-activities 时的原生能力, @capgo/capacitor-live-activities 在 @capgo/capacitor-live-activities 中的实现细节, 使用 @capgo/capacitor-video-player 用于使用 @capgo/capacitor-video-player 时的原生能力, @capgo/capacitor-video-player 在 @capgo/capacitor-video-player 中的实现细节,以及 使用 @capgo/capacitor-native-navigation 用于使用 @capgo/capacitor-native-navigation. 时的原生能力

为 Capacitor 应用提供 Live Updates

当 Web 层出现线上 Bug 时,通过 Capgo 发布修复,而不用等 App Store 审核好几天。用户会在后台收到更新,原生变更则仍走正常审核流程。

博客最新动态

Capgo 为你提供打造真正专业的移动应用所需的最有价值的洞察。