NativeScript 导航路由 #

导航概述 #

NativeScript 提供了灵活的导航系统,支持多种导航模式。

text
┌─────────────────────────────────────────────────────────────┐
│                    导航模式                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  页面导航          Frame-based Navigation                   │
│  ├── 基本导航      navigate / goBack                        │
│  ├── 参数传递      context / navigationContext              │
│  └── 导航动画      transitions                              │
│                                                             │
│  标签导航          Tab Navigation                           │
│  ├── TabView       标签页                                   │
│  └── BottomNavigation 底部导航                              │
│                                                             │
│  模态导航          Modal Navigation                         │
│  ├── 模态页面      showModal                                │
│  └── 关闭模态      closeModal                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Frame 导航 #

基本导航 #

typescript
import { Frame } from '@nativescript/core';

// 导航到新页面
Frame.topmost().navigate('pages/detail/detail-page');

// 返回上一页
Frame.topmost().goBack();

// 返回到根页面
Frame.topmost().goBack();

导航配置 #

typescript
Frame.topmost().navigate({
    moduleName: 'pages/detail/detail-page',
    context: {
        id: 123,
        name: 'John'
    },
    animated: true,
    transition: {
        name: 'slide',
        duration: 300,
        curve: 'easeInOut'
    },
    clearHistory: false
});

导航选项 #

选项 类型 说明
moduleName string 页面模块路径
context any 传递的参数
animated boolean 是否使用动画
transition object 过渡动画配置
clearHistory boolean 是否清除导航历史
backstackVisible boolean 是否在返回栈中可见

参数传递 #

发送参数 #

typescript
// 发送参数
Frame.topmost().navigate({
    moduleName: 'pages/detail/detail-page',
    context: {
        productId: 123,
        productName: 'iPhone 15'
    }
});

接收参数 #

typescript
// detail-page.ts
import { Page, NavigatedData } from '@nativescript/core';

let page: Page;
let productId: number;

export function onNavigatedTo(args: NavigatedData) {
    page = args.object as Page;
    
    if (args.isBackNavigation) {
        return;
    }
    
    const context = page.navigationContext;
    productId = context.productId;
    console.log('Product ID:', productId);
}

返回数据 #

typescript
// 发送页面
export function onSelectItem() {
    Frame.topmost().navigate({
        moduleName: 'pages/item-list/item-list-page',
        context: {
            callback: (selectedItem) => {
                console.log('Selected:', selectedItem);
            }
        }
    });
}

// 选择页面
export function onItemTap(args) {
    const page = args.object.page;
    const context = page.navigationContext;
    
    if (context.callback) {
        context.callback(selectedItem);
    }
    
    Frame.topmost().goBack();
}

导航动画 #

内置动画 #

typescript
// 滑动动画
Frame.topmost().navigate({
    moduleName: 'pages/detail/detail-page',
    transition: {
        name: 'slide'
    }
});

// 淡入淡出
Frame.topmost().navigate({
    moduleName: 'pages/detail/detail-page',
    transition: {
        name: 'fade'
    }
});

// 翻转动画
Frame.topmost().navigate({
    moduleName: 'pages/detail/detail-page',
    transition: {
        name: 'flip'
    }
});

// 无动画
Frame.topmost().navigate({
    moduleName: 'pages/detail/detail-page',
    animated: false
});

动画类型 #

名称 说明
slide 滑动(默认)
fade 淡入淡出
flip 翻转
slideLeft 向左滑动
slideRight 向右滑动
slideTop 向上滑动
slideBottom 向下滑动
explode 爆炸效果

自定义动画 #

typescript
import { Transition, SlideTransition } from '@nativescript/core';

// 自定义过渡
const customTransition: Transition = {
    name: 'custom',
    duration: 500,
    curve: 'spring',
    createAndroidTransition: () => {
        // Android 自定义过渡
    },
    createIOSTransition: () => {
        // iOS 自定义过渡
    }
};

Frame.topmost().navigate({
    moduleName: 'pages/detail/detail-page',
    transition: customTransition
});

页面生命周期 #

生命周期事件 #

xml
<Page navigatingTo="onNavigatingTo" 
      navigatedTo="onNavigatedTo" 
      navigatingFrom="onNavigatingFrom" 
      navigatedFrom="onNavigatedFrom" 
      unloaded="onUnloaded">
    <!-- 页面内容 -->
</Page>
typescript
export function onNavigatingTo(args) {
    console.log('即将导航到此页面');
}

export function onNavigatedTo(args) {
    console.log('已导航到此页面');
    
    if (args.isBackNavigation) {
        console.log('从其他页面返回');
    }
}

export function onNavigatingFrom(args) {
    console.log('即将离开此页面');
}

export function onNavigatedFrom(args) {
    console.log('已离开此页面');
    
    if (args.isBackNavigation) {
        console.log('返回上一页');
    }
}

export function onUnloaded(args) {
    console.log('页面已卸载');
}

生命周期流程 #

text
┌─────────────────────────────────────────────────────────────┐
│                    页面生命周期                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  导航到页面:                                                │
│  navigatingTo → navigatedTo                                 │
│                                                             │
│  离开页面:                                                  │
│  navigatingFrom → navigatedFrom                             │
│                                                             │
│  返回页面:                                                  │
│  navigatingTo (isBackNavigation=true)                       │
│  → navigatedTo (isBackNavigation=true)                      │
│                                                             │
│  页面销毁:                                                  │
│  unloaded                                                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

模态导航 #

显示模态页面 #

typescript
import { Page } from '@nativescript/core';

// 显示模态页面
const modalPage = 'pages/modal/modal-page';
const context = { title: 'Modal Title' };

const result = await page.showModal(modalPage, {
    context: context,
    closeCallback: (result) => {
        console.log('Modal result:', result);
    },
    fullscreen: true,
    animated: true,
    stretched: false
});

模态页面 #

xml
<!-- modal-page.xml -->
<Page xmlns="http://schemas.nativescript.org/tns.xsd" 
      class="modal-page">
    <GridLayout rows="auto, *, auto">
        <Label text="{{ title }}" row="0" class="title" />
        <StackLayout row="1">
            <!-- 模态内容 -->
        </StackLayout>
        <Button text="Close" tap="onClose" row="2" />
    </GridLayout>
</Page>
typescript
// modal-page.ts
import { Page } from '@nativescript/core';

let page: Page;
let closeCallback: Function;

export function onNavigatedTo(args) {
    page = args.object as Page;
    const context = page.navigationContext;
    closeCallback = context.closeCallback;
}

export function onClose() {
    closeCallback({ result: 'success' });
}

模态选项 #

选项 类型 说明
context any 传递的参数
closeCallback function 关闭回调
fullscreen boolean 是否全屏
animated boolean 是否使用动画
stretched boolean 是否拉伸

TabView 导航 #

基本用法 #

xml
<TabView selectedIndex="{{ selectedIndex }}" 
         tabTextColor="#999" 
         selectedTabTextColor="#3498db" 
         tabBackgroundColor="#f5f5f5" 
         selectedIndexChanged="onTabChanged">
    
    <TabView.items>
        <TabViewItem title="Home" iconSource="res://home">
            <TabViewItem.view>
                <GridLayout>
                    <Label text="Home Page" />
                </GridLayout>
            </TabViewItem.view>
        </TabViewItem>
        
        <TabViewItem title="Search" iconSource="res://search">
            <TabViewItem.view>
                <GridLayout>
                    <Label text="Search Page" />
                </GridLayout>
            </TabViewItem.view>
        </TabViewItem>
        
        <TabViewItem title="Profile" iconSource="res://user">
            <TabViewItem.view>
                <GridLayout>
                    <Label text="Profile Page" />
                </GridLayout>
            </TabViewItem.view>
        </TabViewItem>
    </TabView.items>
    
</TabView>

TabView 属性 #

属性 说明
selectedIndex 当前选中的标签索引
tabTextColor 标签文本颜色
selectedTabTextColor 选中标签文本颜色
tabBackgroundColor 标签栏背景色
androidTabsPosition Android 标签位置

BottomNavigation #

Material Design 风格的底部导航:

xml
<BottomNavigation selectedIndex="{{ selectedIndex }}">
    
    <BottomNavigation.items>
        <TabStripItem title="Home">
            <TabStripItem.iconSource>
                <FontIconSource icon="home" fontSize="24" />
            </TabStripItem.iconSource>
        </TabStripItem>
        
        <TabStripItem title="Search">
            <TabStripItem.iconSource>
                <FontIconSource icon="search" fontSize="24" />
            </TabStripItem.iconSource>
        </TabStripItem>
        
        <TabStripItem title="Profile">
            <TabStripItem.iconSource>
                <FontIconSource icon="user" fontSize="24" />
            </TabStripItem.iconSource>
        </TabStripItem>
    </BottomNavigation.items>
    
    <BottomNavigation.content>
        <GridLayout>
            <Label text="{{ 'Page ' + selectedIndex }}" />
        </GridLayout>
    </BottomNavigation.content>
    
</BottomNavigation>

路由守卫 #

Angular 路由守卫 #

typescript
// auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable({
    providedIn: 'root'
})
export class AuthGuard implements CanActivate {
    constructor(
        private authService: AuthService,
        private router: Router
    ) {}
    
    canActivate(): boolean {
        if (this.authService.isLoggedIn()) {
            return true;
        }
        
        this.router.navigate(['/login']);
        return false;
    }
}
typescript
// app.routing.ts
import { NgModule } from '@angular/core';
import { Routes } from '@angular/router';
import { NativeScriptRouterModule } from '@nativescript/angular';
import { AuthGuard } from './auth.guard';

const routes: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full' },
    { path: 'home', component: HomeComponent },
    { 
        path: 'profile', 
        component: ProfileComponent,
        canActivate: [AuthGuard]
    },
    { path: 'login', component: LoginComponent }
];

@NgModule({
    imports: [NativeScriptRouterModule.forRoot(routes)],
    exports: [NativeScriptRouterModule]
})
export class AppRoutingModule {}

Vue 路由守卫 #

typescript
// router/index.ts
import Vue from 'nativescript-vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

const router = new VueRouter({
    routes: [
        { path: '/', component: Home },
        { path: '/login', component: Login },
        { 
            path: '/profile', 
            component: Profile,
            meta: { requiresAuth: true }
        }
    ]
});

router.beforeEach((to, from, next) => {
    if (to.meta.requiresAuth && !isLoggedIn()) {
        next('/login');
    } else {
        next();
    }
});

export default router;

导航最佳实践 #

页面命名规范 #

text
pages/
├── home/
│   ├── home-page.xml
│   ├── home-page.ts
│   └── home-page.css
├── detail/
│   ├── detail-page.xml
│   ├── detail-page.ts
│   └── detail-page.css
└── settings/
    ├── settings-page.xml
    ├── settings-page.ts
    └── settings-page.css

导航服务 #

typescript
// services/navigation.service.ts
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';

@Injectable({
    providedIn: 'root'
})
export class NavigationService {
    constructor(private router: Router) {}
    
    goToDetail(id: number) {
        this.router.navigate(['/detail', id]);
    }
    
    goToProfile() {
        this.router.navigate(['/profile']);
    }
    
    goBack() {
        this.router.back();
    }
}

避免内存泄漏 #

typescript
import { Page, Application } from '@nativescript/core';

export class DetailComponent implements OnInit, OnDestroy {
    private page: Page;
    
    ngOnInit() {
        this.page = Application.getActivePage();
        this.page.on(Page.navigatedFromEvent, this.onNavigatedFrom, this);
    }
    
    ngOnDestroy() {
        this.page.off(Page.navigatedFromEvent, this.onNavigatedFrom, this);
    }
    
    onNavigatedFrom() {
        // 清理资源
    }
}

下一步 #

现在你已经掌握了导航系统,接下来学习 数据绑定,了解数据与视图的绑定方式!

最后更新:2026-03-29