前端开发
在 Vue 3 + Capacitor 跨平台项目中…
适用于已有 Capacitor 6/7/8 与 Vue 3 应用,需要以 Vue 惯用方式集成 Capacitor 插件、监听器、Vue Router 深链、Android 返回键和 PWA Elements。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Vue 3 + Capacitor 特定
解决思路
- 开始前自动检测项目而不是先问用户:检查 vite.config.ts、vite.config.js、quasar.config.js、quasar.config.ts、nuxt.config.ts、package.json、capacitor.config.ts、capacitor.config.json 和现有目录结构;仅当无法检测时才询问用户。
- 逐步引导用户,一次只走一步。
- 判断元框架:确定项目使用纯 Vue (Vite)、Quasar 还是 Nuxt,并据此调整说明。
- Step 1 分析项目:从 package.json 读取 vue 版本。
- 从 package.json 读取 @capacitor/core 版本;如果不存在,说明尚未添加 Capacitor,进入添加 Capacitor 的步骤。
- 按顺序检测元框架:存在 quasar.config.js 或 quasar.config.ts 则按 Quasar 处理并转到 references/quasar.md;存在 nuxt.config.ts 或 nuxt.config.js 则按 Nuxt 处理并转到 references/nuxt.md;存在 vite.config.ts 或 vite.config.js 则按纯 Vue (Vite) 项目继续。
- 检查 android/ 和 ios/ 目录是否存在,判断已添加的平台。
- 检查 capacitor.config.ts 或 capacitor.config.json,判断 Capacitor 配置格式。
- 从 vite.config.ts 或 vite.config.js 读取 build.outDir;默认是 dist。
- Step 2 添加 Capacitor 到 Vue 项目;如果 @capacitor/core 已在 package.json 中则跳过;如果项目是 Quasar 则跳过,因为 Quasar 有自己的 Capacitor 集成,见 references/quasar.md。
- 安装 Capacitor core 和 CLI:npm install @capacitor/core;npm install -D @capacitor/cli。
- 初始化 Capacitor:npx cap init;提示 web directory 时设置为 Step 1 检测到的 Vue 构建输出路径,Vite 项目通常为 dist。
- 检查生成的 capacitor.config.ts 或 capacitor.config.json 中 webDir 是否匹配 Vue 构建输出路径;不匹配则更新。TypeScript 示例:appId: 'com.example.app'、appName: 'my-app'、webDir: 'dist';JSON 示例同样包含 appId、appName、webDir。
- 构建 Vue 应用并添加平台:npm run build;npm install @capacitor/android @capacitor/ios;npx cap add android;npx cap add ios;npx cap sync。
- Step 3 项目结构:android/ 和 ios/ 目录是原生项目,应提交到版本控制。
- src/ 目录是 Vue 应用,也是 Capacitor 应用的 Web 层。
- 把包装 Capacitor 插件的自定义 composables 放在 src/composables/。
- 从 src/ 内的 Vue 组件或 composables 调用 Capacitor 插件。
- Step 4 在 Vue 中使用 Capacitor 插件:Capacitor 插件是普通 TypeScript API,直接在 Composition API 组件中导入并调用。
- 直接用法示例:从 @capacitor/geolocation 导入 Geolocation;定义 latitude 和 longitude 的 ref;在函数中 await Geolocation.getCurrentPosition(),把 position.coords.latitude 和 position.coords.longitude 写入 ref;在模板按钮触发该函数。
- 推荐把插件包装在 composables 中:提供可复用性、封装响应式状态、自动清理。
- useCamera 示例:在 src/composables/useCamera.ts 中定义 photo 和 error 的 ref;takePhoto 和 pickFromGallery 用 try/catch 调用 Camera.getPhoto,参数包括 quality: 90、allowEditing: false、resultType: CameraResultType.Uri、source: CameraSource.Camera 或 CameraSource.Photos;返回 photo、error、takePhoto、pickFromGallery。
- 在组件中使用 useCamera:从 @/composables/useCamera 导入 useCamera,解构 photo、error、takePhoto;模板中按钮触发 takePhoto,显示 error,并在 photo.webPath 存在时显示图片。
- Step 5 用生命周期钩子管理插件事件监听器:必须在 onMounted 注册,在 onUnmounted 移除,防止内存泄漏;Vue 响应式系统会自动跟踪 ref 变化,没有 NgZone 等价问题,但清理仍然关键。
- 创建带自动清理的 composable,例如 useNetwork:定义 status ref 和 listenerHandle;onMounted 中 await Network.getStatus() 并 await Network.addListener('networkStatusChange', ...) 更新 status;onUnmounted 中 await listenerHandle?.remove();返回 status。
- 在组件中使用 useNetwork:导入并解构 status,根据 status.connected 显示 Online 或 Offline。
- App 级监听器通过 App.vue 注册:例如 onMounted 中 await App.addListener('appStateChange', state => ...),onUnmounted 中移除;用于应在整个应用生命周期持续存在的监听器。
- Step 6 平台检测:使用 Capacitor.isNativePlatform() 和 Capacitor.getPlatform() 条件运行仅原生代码。
- 包装 usePlatform composable:返回 platform、isNative、isIos、isAndroid、isWeb;platform 可视为 'web'、'ios' 或 'android'。
- 在组件中使用 usePlatform:例如用 isNative 控制是否显示 Open Device Settings 等原生功能按钮。
- Step 7 用 Vue Router 处理深链:把 Capacitor 的 App.addListener('appUrlOpen', ...) 事件映射到 Vue Router 导航;在 App.vue 或专用 composable 中设置。
- 创建 useDeepLinks composable:onMounted 中注册 appUrlOpen 监听;用 new URL(event.url) 解析 URL,取 url.pathname;如果 path 存在则 router.push(path);onUnmounted 中移除监听。
- 在 App.vue 中使用 useDeepLinks()。
- Step 8 处理 Android 返回按钮:用 App.addListener('backButton', ({ canGoBack }) => ...) 结合 Vue Router。
- 创建 useBackButton composable:onMounted 中先判断 Capacitor.getPlatform() 是否为 android,不是则返回;注册 backButton 监听;canGoBack 为 true 时 router.back(),否则 App.exitApp();onUnmounted 中移除监听。
- 在 App.vue 中使用 useBackButton()。
- Step 9 设置 PWA Elements:如果项目使用 Camera、Toast 等需要 Web 回退 UI 的 Capacitor 插件并面向 Web,先安装:npm install @ionic/pwa-elements。
- 在 src/main.ts 中 createApp() 之前注册自定义元素:import { defineCustomElements } from '@ionic/pwa-elements/loader';调用 defineCustomElements(window);然后再 createApp(App)、app.use(router)、app.mount('#app')。
- Step 10 构建和同步工作流:修改 Vue 应用后运行 npm run build 和 npx cap sync。
- 在设备或模拟器运行:npx cap run android;npx cap run ios。
- 打开原生 IDE 做高级配置或调试:npx cap open android;npx cap open ios。
- 开发时实时重载:npx cap run android --livereload --external;npx cap run ios --livereload --external;这会内部启动 Vite dev server 并让原生应用从开发服务器加载。
- 错误处理 webDir 不匹配:如果 npx cap sync 复制了错误文件,检查 capacitor.config.ts 或 capacitor.config.json 的 webDir 是否匹配 Vue 构建输出路径;Vite 项目默认是 dist。
- 错误处理插件运行时找不到:安装任何新插件后运行 npx cap sync;确认插件出现在 package.json dependencies 中。
- 错误处理监听器内存泄漏:始终在 onUnmounted 移除插件监听器;保存 addListener 返回的 PluginListenerHandle,并在卸载时调用 handle.remove()。
- 错误处理深链不工作:检查原生项目是否配置 URL scheme 或 universal links;Android 查看 android/app/src/main/AndroidManifest.xml,iOS 查看 ios/App/App/Info.plist 和 associated domain entitlement;确认 App.vue 中调用了 useDeepLinks()。
- 错误处理返回键意外关闭应用:确保 backButton 监听先检查 canGoBack 再调用 App.exitApp();只有没有导航历史时才退出。
- 错误处理 PWA Elements 在 Web 不渲染:确认 src/main.ts 中在 createApp() 之前调用了 defineCustomElements(window);确认已安装 @ionic/pwa-elements。
- 错误处理 Quasar 项目未检测到 Capacitor:使用 quasar mode add capacitor,而不是手动安装 Capacitor;见 references/quasar.md。
- 错误处理 Nuxt 项目构建输出不兼容:Nuxt 默认 SSR 输出与 Capacitor 不兼容;必须在 nuxt.config.ts 中设置 ssr: false 生成静态 SPA;见 references/nuxt.md。
适用边界 · 注意事项
- 不要用于从零创建新的 Capacitor 应用、升级 Capacitor 版本、安装具体插件、搭建 Ionic Framework with Vue,或非 Vue 框架项目。
- 未使用 Vue 3 或 Capacitor 6/7/8 的项目不适用。
- 没有 Node.js/npm,或缺少 Xcode/Android Studio 时,无法完成对应 iOS/Android 原生步骤。