NativeScript Angular集成 #

Angular 集成概述 #

NativeScript 与 Angular 深度集成,让你可以使用 Angular 的完整生态系统开发原生应用。

text
┌─────────────────────────────────────────────────────────────┐
│                    Angular NativeScript                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  核心特性                                                    │
│  ├── 完整的 Angular 支持                                    │
│  ├── TypeScript 原生支持                                    │
│  ├── 依赖注入                                               │
│  ├── 路由系统                                               │
│  ├── 表单处理                                               │
│  └── HTTP 客户端                                            │
│                                                             │
│  NativeScript 扩展                                          │
│  ├── 原生 UI 组件                                           │
│  ├── 原生路由                                               │
│  └── 原生模块                                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

项目创建 #

创建 Angular 项目 #

bash
ns create my-app --ng

项目结构 #

text
my-app/
├── src/
│   ├── app/
│   │   ├── app.component.html
│   │   ├── app.component.ts
│   │   ├── app.module.ts
│   │   ├── app.routing.ts
│   │   └── home/
│   │       ├── home.component.html
│   │       ├── home.component.ts
│   │       └── home.module.ts
│   ├── environments/
│   ├── main.ts
│   └── styles.css
├── angular.json
├── package.json
└── tsconfig.json

模块配置 #

AppModule #

typescript
// app.module.ts
import { NgModule } from '@angular/core';
import { NativeScriptModule } from '@nativescript/angular';
import { AppRoutingModule } from './app.routing';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';

@NgModule({
    declarations: [AppComponent, HomeComponent],
    imports: [
        NativeScriptModule,
        AppRoutingModule
    ],
    bootstrap: [AppComponent]
})
export class AppModule {}

启动应用 #

typescript
// main.ts
import { platformNativeScriptDynamic } from '@nativescript/angular';
import { AppModule } from './app.module';

platformNativeScriptDynamic().bootstrapModule(AppModule);

组件开发 #

基本组件 #

typescript
// home.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'ns-home',
    templateUrl: './home.component.html',
    styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
    title = 'Home';
    items: string[] = [];
    
    ngOnInit() {
        this.items = ['Item 1', 'Item 2', 'Item 3'];
    }
    
    onItemTap(item: string) {
        console.log('Tapped:', item);
    }
}
xml
<!-- home.component.html -->
<ActionBar title="Home">
    <ActionItem text="Add" (tap)="onAdd()"></ActionItem>
</ActionBar>

<GridLayout>
    <ListView [items]="items" class="list-group">
        <ng-template let-item="item">
            <Label [text]="item" class="list-group-item" (tap)="onItemTap(item)"></Label>
        </ng-template>
    </ListView>
</GridLayout>

组件通信 #

typescript
// 父组件
@Component({
    selector: 'ns-parent',
    template: `
        <GridLayout>
            <ns-child [data]="data" (dataChange)="onDataChange($event)"></ns-child>
        </GridLayout>
    `
})
export class ParentComponent {
    data = 'Hello';
    
    onDataChange(newValue: string) {
        this.data = newValue;
    }
}

// 子组件
@Component({
    selector: 'ns-child',
    template: `
        <Label [text]="data" (tap)="onChange()"></Label>
    `
})
export class ChildComponent {
    @Input() data: string;
    @Output() dataChange = new EventEmitter<string>();
    
    onChange() {
        this.dataChange.emit('New Value');
    }
}

路由配置 #

路由定义 #

typescript
// app.routing.ts
import { NgModule } from '@angular/core';
import { Routes } from '@angular/router';
import { NativeScriptRouterModule } from '@nativescript/angular';

const routes: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full' },
    { path: 'home', component: HomeComponent },
    { 
        path: 'detail/:id', 
        component: DetailComponent,
        canActivate: [AuthGuard]
    },
    { path: 'settings', loadChildren: () => import('./settings/settings.module').then(m => m.SettingsModule) }
];

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

路由导航 #

typescript
import { Router, ActivatedRoute } from '@angular/router';

@Component({
    // ...
})
export class HomeComponent {
    constructor(private router: Router) {}
    
    goToDetail(id: number) {
        this.router.navigate(['/detail', id]);
    }
    
    goToSettings() {
        this.router.navigate(['/settings']);
    }
}

@Component({
    // ...
})
export class DetailComponent implements OnInit {
    id: number;
    
    constructor(private route: ActivatedRoute) {}
    
    ngOnInit() {
        this.id = +this.route.snapshot.paramMap.get('id');
        
        // 或订阅参数变化
        this.route.paramMap.subscribe(params => {
            this.id = +params.get('id');
        });
    }
}

路由守卫 #

typescript
// guards/auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthService } from '../services/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
// services/user.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
    providedIn: 'root'
})
export class UserService {
    private apiUrl = 'https://api.example.com';
    
    constructor(private http: HttpClient) {}
    
    getUsers(): Observable<User[]> {
        return this.http.get<User[]>(`${this.apiUrl}/users`);
    }
    
    getUser(id: number): Observable<User> {
        return this.http.get<User>(`${this.apiUrl}/users/${id}`);
    }
    
    createUser(user: CreateUserDto): Observable<User> {
        return this.http.post<User>(`${this.apiUrl}/users`, user);
    }
}

使用服务 #

typescript
@Component({
    selector: 'ns-users',
    templateUrl: './users.component.html'
})
export class UsersComponent implements OnInit {
    users: User[] = [];
    
    constructor(private userService: UserService) {}
    
    ngOnInit() {
        this.loadUsers();
    }
    
    loadUsers() {
        this.userService.getUsers().subscribe(users => {
            this.users = users;
        });
    }
}

表单处理 #

模板驱动表单 #

typescript
// app.module.ts
import { NativeScriptFormsModule } from '@nativescript/angular';

@NgModule({
    imports: [
        NativeScriptModule,
        NativeScriptFormsModule
    ]
})
export class AppModule {}
xml
<!-- login.component.html -->
<GridLayout>
    <StackLayout>
        <TextField [(ngModel)]="email" hint="Email" keyboardType="email"></TextField>
        <TextField [(ngModel)]="password" hint="Password" secure="true"></TextField>
        <Button text="Login" (tap)="onLogin()"></Button>
    </StackLayout>
</GridLayout>
typescript
// login.component.ts
@Component({
    selector: 'ns-login',
    templateUrl: './login.component.html'
})
export class LoginComponent {
    email = '';
    password = '';
    
    constructor(private authService: AuthService) {}
    
    onLogin() {
        this.authService.login(this.email, this.password);
    }
}

响应式表单 #

typescript
// app.module.ts
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
    imports: [
        NativeScriptModule,
        ReactiveFormsModule
    ]
})
export class AppModule {}
typescript
// register.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
    selector: 'ns-register',
    templateUrl: './register.component.html'
})
export class RegisterComponent {
    registerForm: FormGroup;
    
    constructor(private fb: FormBuilder) {
        this.registerForm = this.fb.group({
            name: ['', [Validators.required, Validators.minLength(2)]],
            email: ['', [Validators.required, Validators.email]],
            password: ['', [Validators.required, Validators.minLength(6)]],
            confirmPassword: ['', Validators.required]
        }, { validators: this.passwordMatchValidator });
    }
    
    passwordMatchValidator(form: FormGroup) {
        const password = form.get('password');
        const confirmPassword = form.get('confirmPassword');
        return password.value === confirmPassword.value ? null : { mismatch: true };
    }
    
    onSubmit() {
        if (this.registerForm.valid) {
            console.log(this.registerForm.value);
        }
    }
}
xml
<!-- register.component.html -->
<GridLayout>
    <StackLayout [formGroup]="registerForm">
        <TextField formControlName="name" hint="Name"></TextField>
        <Label *ngIf="registerForm.get('name').errors?.required" text="Name is required" color="red"></Label>
        
        <TextField formControlName="email" hint="Email" keyboardType="email"></TextField>
        <Label *ngIf="registerForm.get('email').errors?.email" text="Invalid email" color="red"></Label>
        
        <TextField formControlName="password" hint="Password" secure="true"></TextField>
        <TextField formControlName="confirmPassword" hint="Confirm Password" secure="true"></TextField>
        
        <Button text="Register" (tap)="onSubmit()" [isEnabled]="registerForm.valid"></Button>
    </StackLayout>
</GridLayout>

懒加载 #

懒加载模块 #

typescript
// settings/settings.module.ts
import { NgModule } from '@angular/core';
import { NativeScriptCommonModule } from '@nativescript/angular';
import { SettingsComponent } from './settings.component';
import { SettingsRoutingModule } from './settings.routing';

@NgModule({
    declarations: [SettingsComponent],
    imports: [
        NativeScriptCommonModule,
        SettingsRoutingModule
    ]
})
export class SettingsModule {}
typescript
// settings/settings.routing.ts
import { NgModule } from '@angular/core';
import { Routes } from '@angular/router';
import { NativeScriptRouterModule } from '@nativescript/angular';
import { SettingsComponent } from './settings.component';

const routes: Routes = [
    { path: '', component: SettingsComponent }
];

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

最佳实践 #

组件命名 #

text
┌─────────────────────────────────────────────────────────────┐
│                    命名规范                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  组件                                                       │
│  ├── 文件名: user-list.component.ts                         │
│  ├── 类名: UserListComponent                                │
│  └── 选择器: ns-user-list                                   │
│                                                             │
│  服务                                                       │
│  ├── 文件名: user.service.ts                                │
│  └── 类名: UserService                                      │
│                                                             │
│  模块                                                       │
│  ├── 文件名: user.module.ts                                 │
│  └── 类名: UserModule                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

下一步 #

现在你已经掌握了 Angular 集成,接下来学习 Vue集成,了解如何与 Vue 框架集成!

最后更新:2026-03-29