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="" 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