NativeScript-Vue集成Firebase时$navigateTo报Failed to resolve Frame错误
NativeScript-Vue + Firebase 导航报错:无法找到Frame组件
问题场景
我开发了一个基于Firebase的NativeScript-Vue应用,代码如下,但运行时提示无法找到指定的Frame,尽管已经在App.vue中定义了id为main-frame的Frame组件。
应用代码
src/components/App.vue
<script setup lang="ts"> import { firebase } from '@nativescript/firebase-core'; import '@nativescript/firebase-auth'; import { $navigateTo, ActionBar, onMounted } from 'nativescript-vue'; import Login from './pages/Login.vue'; import Home from './pages/Home.vue'; onMounted(() => { firebase().auth().addAuthStateChangeListener(async user => { if (!user) { console.log("No user is signed in, navigating to Login"); $navigateTo(Login, { frame: 'main-frame', clearHistory: true }); } else { console.log("User is signed in, navigating to Home"); $navigateTo(Home, { frame: 'main-frame', clearHistory: true }); } }) }) </script> <template> <Frame id="main-frame"> <ActionBar title="My App" class="action-bar" /> </Frame> </template>
src/components/pages/Home.vue
<script setup lang="ts"> import { firebase } from '@nativescript/firebase-core'; import '@nativescript/firebase-auth'; const logout = async () => { try { await firebase().auth().signOut(); console.log("User signed out successfully"); } catch (error) { console.error("Error signing out:", error); } } </script> <template> <Page> <StackLayout> <Label text="Welcome to the Home Page!" class="h1 text-center" /> <Button @tap="logout" text="Logout" /> </StackLayout> </Page> </template>
src/components/pages/Login.vue
<script setup lang="ts"> import { ref, computed, onMounted, onUnmounted } from 'nativescript-vue'; import { firebase } from '@nativescript/firebase-core'; import '@nativescript/firebase-auth'; import { GoogleAuthProvider } from '@nativescript/firebase-auth'; import { GoogleSignin } from '@nativescript/google-signin'; const handleLogin = async () => { try { const googleUser = await GoogleSignin.signIn(); const credential = GoogleAuthProvider.credential(googleUser.idToken, googleUser.accessToken); await firebase().auth().signInWithCredential(credential); } catch (error) { console.error('Login failed', error); } } </script> <template> <Page actionBarHidden="true"> <StackLayout class="p-10" verticalAlignment="center" horizontalAlignment="center"> <Label text="Welcome! Please log in." class="h1 text-center mb-10" /> <Button @tap="handleLogin" text="Login with Google" class="btn btn-primary" /> </StackLayout> </Page> </template>
src/app.ts
import { createApp } from 'nativescript-vue'; import App from './components/App.vue'; createApp(App).start();
错误信息
[$navigateTo] Failed to navigate: Error: Failed to resolve frame. Make sure your frame exists. at $navigateTo (file: src/webpack:/moonhope-finance-ns/node_modules/nativescript-vue/dist/plugins/navigation.js:32:0) at file: src/webpack:/moonhope-finance-ns/src/components/App.vue:12:18 at com.google.firebase.auth.FirebaseAuth.AuthStateListener.onAuthStateChanged (file: src/webpack:/moonhope-finance-ns/node_modules/@nativescript/firebase-auth/index.android.js:827:0)
解决方案
核心原因
- Vue的
onMounted钩子触发时,NativeScript的Frame组件可能还未完成Native层面的初始化,导致通过id查找Frame实例失败。 - Firebase的auth状态监听可能在Frame完全就绪前就触发了导航操作。
修复方案
方案1:通过Vue Ref直接绑定Frame实例(推荐)
直接通过Vue的ref获取Frame组件实例,避免通过id查找的延迟问题:
<!-- 修改后的src/components/App.vue --> <script setup lang="ts"> import { firebase } from '@nativescript/firebase-core'; import '@nativescript/firebase-auth'; import { $navigateTo, onMounted, ref } from 'nativescript-vue'; import Login from './pages/Login.vue'; import Home from './pages/Home.vue'; // 创建ref绑定Frame组件 const mainFrame = ref(null); onMounted(() => { firebase().auth().addAuthStateChangeListener(async user => { if (!user) { console.log("No user is signed in, navigating to Login"); // 使用ref指向的Frame实例 $navigateTo(Login, { frame: mainFrame.value, clearHistory: true }); } else { console.log("User is signed in, navigating to Home"); $navigateTo(Home, { frame: mainFrame.value, clearHistory: true }); } }) }) </script> <template> <!-- 添加ref属性绑定到mainFrame --> <Frame ref="mainFrame" id="main-frame"> <ActionBar title="My App" class="action-bar" /> </Frame> </template>
方案2:监听Frame的Loaded事件
等Frame完全加载完成后再注册auth状态监听,确保导航时Frame已就绪:
<!-- 修改后的src/components/App.vue --> <script setup lang="ts"> import { firebase } from '@nativescript/firebase-core'; import '@nativescript/firebase-auth'; import { $navigateTo, ref } from 'nativescript-vue'; import Login from './pages/Login.vue'; import Home from './pages/Home.vue'; const mainFrame = ref(null); let authStateListener = null; // Frame加载完成后注册auth监听 const onFrameLoaded = () => { authStateListener = firebase().auth().addAuthStateChangeListener(async user => { if (!user) { console.log("No user is signed in, navigating to Login"); $navigateTo(Login, { frame: mainFrame.value, clearHistory: true }); } else { console.log("User is signed in, navigating to Home"); $navigateTo(Home, { frame: mainFrame.value, clearHistory: true }); } }); }; // 组件卸载时移除监听,防止内存泄漏 const onFrameUnloaded = () => { if (authStateListener) { authStateListener(); } }; </script> <template> <Frame ref="mainFrame" id="main-frame" @loaded="onFrameLoaded" @unloaded="onFrameUnloaded" > <ActionBar title="My App" class="action-bar" /> </Frame> </template>
方案3:延迟执行导航逻辑
通过setTimeout给Frame预留初始化时间,适合快速测试:
<!-- 修改后的src/components/App.vue --> <script setup lang="ts"> import { firebase } from '@nativescript/firebase-core'; import '@nativescript/firebase-auth'; import { $navigateTo, onMounted } from 'nativescript-vue'; import Login from './pages/Login.vue'; import Home from './pages/Home.vue'; onMounted(() => { // 延迟500ms执行,确保Frame初始化完成 setTimeout(() => { firebase().auth().addAuthStateChangeListener(async user => { if (!user) { console.log("No user is signed in, navigating to Login"); $navigateTo(Login, { frame: 'main-frame', clearHistory: true }); } else { console.log("User is signed in, navigating to Home"); $navigateTo(Home, { frame: 'main-frame', clearHistory: true }); } }); }, 500); }) </script> <template> <Frame id="main-frame"> <ActionBar title="My App" class="action-bar" /> </Frame> </template>
内容的提问来源于stack exchange,提问作者starleaf1
相关产品推荐
相关产品推荐

