NativeScript 基础语法 #

XML 布局基础 #

基本结构 #

NativeScript 使用 XML 文件定义用户界面:

xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd">
    <ActionBar title="My App" />
    
    <GridLayout>
        <Label text="Hello World!" />
    </GridLayout>
</Page>

页面结构 #

text
┌─────────────────────────────────────────────────────────────┐
│                    页面结构                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  <Page>                                                     │
│      ├── <ActionBar>     顶部导航栏                         │
│      │   ├── <ActionItem>  操作按钮                         │
│      │   └── <NavigationButton>  导航按钮                   │
│      │                                                      │
│      └── 内容区域                                           │
│          ├── <GridLayout>     网格布局                      │
│          ├── <StackLayout>    堆叠布局                      │
│          ├── <FlexboxLayout>  弹性布局                      │
│          └── 其他布局组件                                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

ActionBar 组件 #

xml
<Page>
    <ActionBar title="Home" class="action-bar">
        <!-- 导航按钮 -->
        <NavigationButton text="Back" tap="onBack" />
        
        <!-- 操作项 -->
        <ActionItem text="Edit" 
                    tap="onEdit" 
                    android.position="actionBar" 
                    ios.position="right" />
        
        <!-- 溢出菜单 -->
        <ActionItem text="Settings" 
                    tap="onSettings" 
                    android.position="popup" />
    </ActionBar>
    
    <GridLayout>
        <!-- 页面内容 -->
    </GridLayout>
</Page>

布局容器 #

StackLayout #

垂直或水平堆叠子元素:

xml
<!-- 垂直堆叠(默认) -->
<StackLayout orientation="vertical">
    <Label text="Item 1" />
    <Label text="Item 2" />
    <Label text="Item 3" />
</StackLayout>

<!-- 水平堆叠 -->
<StackLayout orientation="horizontal">
    <Button text="Button 1" />
    <Button text="Button 2" />
    <Button text="Button 3" />
</StackLayout>

GridLayout #

网格布局,使用行和列:

xml
<GridLayout rows="auto, *, auto" columns="*, *">
    <!-- 第一行 -->
    <Label text="Header" row="0" col="0" colSpan="2" />
    
    <!-- 第二行 -->
    <Label text="Left" row="1" col="0" />
    <Label text="Right" row="1" col="1" />
    
    <!-- 第三行 -->
    <Button text="Footer" row="2" col="0" colSpan="2" />
</GridLayout>

FlexboxLayout #

类似 CSS Flexbox:

xml
<FlexboxLayout flexDirection="row" 
               flexWrap="wrap" 
               justifyContent="space-between">
    <Label text="1" width="30%" />
    <Label text="2" width="30%" />
    <Label text="3" width="30%" />
    <Label text="4" width="30%" />
</FlexboxLayout>

AbsoluteLayout #

绝对定位:

xml
<AbsoluteLayout>
    <Label text="Top Left" top="0" left="0" />
    <Label text="Top Right" top="0" right="0" />
    <Label text="Bottom Left" bottom="0" left="0" />
    <Label text="Bottom Right" bottom="0" right="0" />
</AbsoluteLayout>

DockLayout #

停靠布局:

xml
<DockLayout stretchLastChild="true">
    <Label text="Top" dock="top" height="50" />
    <Label text="Bottom" dock="bottom" height="50" />
    <Label text="Left" dock="left" width="100" />
    <Label text="Right" dock="right" width="100" />
    <Label text="Center" />
</DockLayout>

WrapLayout #

自动换行布局:

xml
<WrapLayout orientation="horizontal">
    <Label text="Item 1" width="100" height="100" />
    <Label text="Item 2" width="100" height="100" />
    <Label text="Item 3" width="100" height="100" />
    <Label text="Item 4" width="100" height="100" />
</WrapLayout>

基础 UI 组件 #

Label #

文本显示:

xml
<Label text="Hello World" 
       textWrap="true" 
       class="title" />

Button #

按钮:

xml
<Button text="Click Me" 
        tap="onTap" 
        class="btn btn-primary" />

<!-- 带图标的按钮 -->
<Button text="Save" 
        tap="onSave" 
        class="btn">
    <FormattedString>
        <Span text="&#xf0c7;" class="fas" />
        <Span text=" Save" />
    </FormattedString>
</Button>

TextField #

单行输入:

xml
<TextField hint="Enter your name" 
           text="{{ name }}" 
           keyboardType="name" 
           returnKeyType="done" 
           autocorrect="false" />

TextView #

多行输入:

xml
<TextView hint="Enter your message" 
          text="{{ message }}" 
          editable="true" 
          textWrap="true" />

Switch #

开关:

xml
<Switch checked="{{ isEnabled }}" 
        checkedChange="onCheckedChange" />

Slider #

滑块:

xml
<Slider minValue="0" 
        maxValue="100" 
        value="{{ volume }}" 
        valueChange="onVolumeChange" />

Progress #

进度条:

xml
<Progress value="{{ progress }}" 
           maxValue="100" />

ActivityIndicator #

加载指示器:

xml
<ActivityIndicator busy="{{ isLoading }}" 
                    width="50" 
                    height="50" />

Image #

图片:

xml
<!-- 本地图片 -->
<Image src="~/assets/images/logo.png" 
       stretch="aspectFit" />

<!-- 网络图片 -->
<Image src="https://example.com/image.jpg" 
       stretch="aspectFill" 
       loadMode="async" />

<!-- Base64 图片 -->
<Image src="data:image/png;base64,..." />

ListView #

列表视图:

xml
<ListView items="{{ items }}" 
          itemTap="onItemTap" 
          class="list-group">
    <ListView.itemTemplate>
        <GridLayout columns="auto, *" rows="auto">
            <Image src="{{ image }}" 
                   row="0" col="0" 
                   width="50" height="50" />
            <Label text="{{ title }}" 
                   row="0" col="1" 
                   class="list-group-item" />
        </GridLayout>
    </ListView.itemTemplate>
</ListView>

属性绑定 #

基本绑定 #

xml
<!-- 单向绑定 -->
<Label text="{{ message }}" />

<!-- 双向绑定 -->
<TextField text="{{ name }}" />

表达式绑定 #

xml
<!-- 条件表达式 -->
<Label text="{{ isActive ? 'Active' : 'Inactive' }}" />

<!-- 算术表达式 -->
<Label text="{{ 'Count: ' + count }}" />

绑定到对象属性 #

xml
<Label text="{{ user.name }}" />
<Label text="{{ user.address.city }}" />

事件处理 #

基本事件 #

xml
<Button text="Click" tap="onTap" />
<TextField textChange="onTextChange" />
<Switch checkedChange="onCheckedChange" />

事件处理器 #

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

export function onTap(args: EventData) {
    const button = args.object as Button;
    console.log('Button tapped');
}

export function onTextChange(args: EventData) {
    const textField = args.object as TextField;
    console.log('Text:', textField.text);
}

页面事件 #

xml
<Page navigatingTo="onNavigatingTo" 
      navigatedTo="onNavigatedTo" 
      navigatingFrom="onNavigatingFrom" 
      navigatedFrom="onNavigatedFrom">
    <!-- 页面内容 -->
</Page>
typescript
import { Page, NavigatedData } from '@nativescript/core';

export function onNavigatingTo(args: NavigatedData) {
    console.log('Navigating to page');
}

export function onNavigatedTo(args: NavigatedData) {
    console.log('Navigated to page');
}

数据绑定进阶 #

Observable 对象 #

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

class UserViewModel extends Observable {
    private _name: string = '';
    private _email: string = '';
    
    get name(): string {
        return this._name;
    }
    
    set name(value: string) {
        if (this._name !== value) {
            this._name = value;
            this.notifyPropertyChange('name', value);
        }
    }
    
    get email(): string {
        return this._email;
    }
    
    set email(value: string) {
        if (this._email !== value) {
            this._email = value;
            this.notifyPropertyChange('email', value);
        }
    }
}

ObservableArray #

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

export class ListViewModel extends Observable {
    items: ObservableArray<any>;
    
    constructor() {
        super();
        this.items = new ObservableArray([
            { title: 'Item 1' },
            { title: 'Item 2' },
            { title: 'Item 3' }
        ]);
    }
    
    addItem() {
        this.items.push({ title: 'New Item' });
    }
    
    removeItem(index: number) {
        this.items.splice(index, 1);
    }
}

绑定上下文 #

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

export function onNavigatingTo(args) {
    const page = args.object as Page;
    page.bindingContext = new UserViewModel();
}

样式基础 #

内联样式 #

xml
<Label text="Hello" 
       style="color: red; font-size: 20; background-color: #f0f0f0;" />

CSS 类 #

xml
<Label text="Hello" class="title primary" />
css
.title {
    font-size: 24;
    font-weight: bold;
}

.primary {
    color: #3498db;
}

平台特定样式 #

css
/* Android 特定 */
.android .title {
    font-size: 20;
}

/* iOS 特定 */
.ios .title {
    font-size: 24;
}

状态样式 #

css
/* 按下状态 */
Button:active {
    background-color: #2980b9;
}

/* 禁用状态 */
Button:disabled {
    opacity: 0.5;
}

条件渲染 #

使用 visibility #

xml
<Label text="Admin Only" visibility="{{ isAdmin ? 'visible' : 'collapsed' }}" />

使用 ngIf (Angular) #

xml
<Label *ngIf="isAdmin" text="Admin Only"></Label>

使用 v-if (Vue) #

vue
<Label v-if="isAdmin" text="Admin Only" />

循环渲染 #

ListView #

xml
<ListView items="{{ items }}">
    <ListView.itemTemplate>
        <Label text="{{ title }}" />
    </ListView.itemTemplate>
</ListView>

Repeater #

xml
<Repeater items="{{ items }}">
    <Repeater.itemTemplate>
        <Label text="{{ title }}" />
    </Repeater.itemTemplate>
</Repeater>

ngFor (Angular) #

xml
<StackLayout *ngFor="let item of items">
    <Label [text]="item.title"></Label>
</StackLayout>

v-for (Vue) #

vue
<StackLayout v-for="item in items" :key="item.id">
    <Label :text="item.title" />
</StackLayout>

页面导航 #

编程式导航 #

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

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

// 带参数导航
Frame.topmost().navigate({
    moduleName: 'pages/detail/detail-page',
    context: { id: 123 },
    transition: {
        name: 'slide',
        duration: 300
    }
});

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

接收导航参数 #

typescript
export function onNavigatedTo(args) {
    const page = args.object;
    const context = page.navigationContext;
    console.log('Received id:', context.id);
}

最佳实践 #

代码组织 #

text
┌─────────────────────────────────────────────────────────────┐
│                    文件组织                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  每个页面/组件包含三个文件:                                 │
│                                                             │
│  user-profile/                                              │
│  ├── user-profile.xml     # 布局                            │
│  ├── user-profile.ts      # 逻辑                            │
│  └── user-profile.css     # 样式                            │
│                                                             │
│  命名规范:                                                  │
│  - 文件名:小写 + 连字符                                    │
│  - 类名:大驼峰                                             │
│  - 变量/函数:小驼峰                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

性能优化 #

xml
<!-- 使用 onItemLoading 优化 ListView -->
<ListView items="{{ items }}" 
          itemLoading="onItemLoading">
    <ListView.itemTemplate>
        <!-- 简化的模板 -->
    </ListView.itemTemplate>
</ListView>
typescript
// 避免频繁更新
import { Observable } from '@nativescript/core';

class ViewModel extends Observable {
    // 批量更新
    updateData(data: any) {
        this.set('name', data.name);
        this.set('email', data.email);
        // ...
    }
}

下一步 #

现在你已经掌握了基础语法,接下来学习 UI组件,深入了解 NativeScript 的丰富组件库!

最后更新:2026-03-29