旅游攻略 - 详情页跳转实现旅行规划助手 ArkTS原生


1. 应用概述
旅游攻略(TravelGuide)是一款基于HarmonyOS ArkTS框架开发的内容类工具应用,核心功能是展示旅游攻略和景点介绍。与之前介绍的出行预订类应用不同,旅游攻略应用更注重内容展示,采用了标题行加内容列表的设计模式。
从技术实现角度来看,旅游攻略应用充分利用了 ArkUI 框架的内容展示能力。通过 @State 装饰器管理攻略列表,通过 Row 组件实现标题行设计,通过 ForEach 组件实现攻略列表渲染。应用的结构展示了如何设计内容资讯类的列表页面。
本技术博客将从应用架构设计、核心代码实现、标题行设计、数据模型设计、列表渲染实现、UI 布局设计等多个维度,对这款旅游攻略应用进行全面的技术剖析。通过本文的深入讲解,读者能够掌握 HarmonyOS ArkTS 开发中内容展示类应用的设计模式,以及如何实现资讯、攻略类页面的布局。
2. 技术架构分析
2.1 整体架构设计
旅游攻略应用采用了标准的单页面架构,整个应用包含标题行和攻略列表区域两个核心部分。与之前的出行预订类应用相比,旅游攻略应用没有查询输入框和分类标签,而是使用了内容标题行的设计。
┌─────────────────────────────────────────────────────────┐
│ TravelGuide页面 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ CommonTitleBar组件 │ │
│ │ (导航栏+标题显示) │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 标题行区域 │ │
│ │ 热门目的地 更多 │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ [加载攻略按钮] │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 攻略列表区域 │ │
│ │ (List + ForEach + ListItem) │ │
│ │ 每个Item包含: │ │
│ │ - 攻略标题 │ │
│ │ - 作者、浏览量 │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
旅游攻略应用的创新点在于标题行设计,左侧显示主标题,右侧显示辅助操作。
2.2 模块依赖关系
从依赖关系的角度分析,旅游攻略应用主要依赖以下几个核心模块:
首先是 CommonTitleBar 组件,该组件提供了统一的页面标题栏和返回按钮功能。
其次是 ArkUI 的基础组件:
- Column:列布局容器,用于垂直排列子组件
- Row:行布局容器,用于水平排列标题行元素
- Text:文本组件,用于显示攻略标题、作者等信息
- Button:按钮组件,用于触发加载操作
- List:列表容器组件,用于展示攻略列表
- ListItem:列表项组件,对应单个攻略
- ForEach:循环渲染组件,用于渲染攻略列表
- Blank:空白填充组件
2.3 数据模型设计
旅游攻略应用的数据模型相对简单:
@State app_guides: Record<string, string>[] = [];
| 状态变量 | 类型 | 初始值 | 说明 |
|---|---|---|---|
| app_guides | Record<string, string>[] | [] | 攻略数组,初始为空 |
攻略的数据结构采用 Record 类型:
Record<string, string> = {
'title': '北京三日游攻略', // string 攻略标题
'author': '旅游达人', // string 作者
'views': '2.3万' // string 浏览量
}
2.4 与其他应用的对比
旅游攻略应用与其他内容类应用的对比:
| 特性 | 电影票 | 火车票/机票 | 酒店预订 | 旅游攻略 |
|---|---|---|---|---|
| 筛选方式 | 无 | 查询输入 | 分类标签 | 标题行 |
| 列表项内容 | 电影+价格 | 车次/航班+价格 | 酒店+评分+价格 | 标题+作者+浏览量 |
| 价格信息 | 有 | 有 | 有 | 无 |
| 用户信息 | 无 | 无 | 无 | 有(作者) |
3. 核心代码详解
3.1 标题行区域实现
标题行是旅游攻略应用的特色功能:
Row({ space: 16 }) {
Column() {
Text('热门目的地')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.app_color_text_primary'))
}
.layoutWeight(1)
Column() {
Text('更多')
.fontSize(14)
.fontColor($r('app.color.app_color_primary'))
}
}
标题行的结构:
┌─────────────────────────────────────────────────────────┐
│ 热门目的地 更多 │
│ (主标题,加粗) (副标题) │
└─────────────────────────────────────────────────────────┘
标题行设计要点:
- 左侧主标题使用加粗样式
- 右侧辅助操作使用较小字体
- layoutWeight(1) 让左侧占据主要空间
- 右侧"更多"使用主题色,暗示可点击
3.2 标题行样式对比
主标题样式:
Text('热门目的地')
.fontSize(16)
.fontWeight(FontWeight.Bold) // 加粗
.fontColor($r('app.color.app_color_text_primary')) // 主文本色
副标题样式:
Text('更多')
.fontSize(14) // 较小字体
.fontColor($r('app.color.app_color_primary')) // 主题色
| 元素 | 字体大小 | 字体权重 | 字体颜色 |
|---|---|---|---|
| 主标题 | 16 | Bold | app_color_text_primary |
| 副标题 | 14 | Normal | app_color_primary |
3.3 加载攻略功能
攻略列表需要用户点击按钮加载:
Button('加载攻略')
.width('100%')
.onClick(() => {
this.app_guides = [
{ 'title': '北京三日游攻略', 'author': '旅游达人', 'views': '2.3万' },
{ 'title': '上海迪士尼游玩指南', 'author': '小可爱', 'views': '1.8万' },
{ 'title': '成都美食攻略', 'author': '吃货一枚', 'views': '3.5万' },
{ 'title': '杭州西湖游览路线', 'author': '风景摄影', 'views': '1.2万' }
];
})
加载攻略的数据:
| 标题 | 作者 | 浏览量 |
|---|---|---|
| 北京三日游攻略 | 旅游达人 | 2.3万 |
| 上海迪士尼游玩指南 | 小可爱 | 1.8万 |
| 成都美食攻略 | 吃货一枚 | 3.5万 |
| 杭州西湖游览路线 | 风景摄影 | 1.2万 |
3.4 攻略列表渲染机制
ForEach 组件渲染攻略列表:
List() {
ForEach(this.app_guides, (app_guide: Record<string, string>) => {
ListItem() {
Column({ space: 8 }) {
Text(app_guide['title'])
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor($r('app.color.app_color_text_primary'))
.width('100%')
Row() {
Text(app_guide['author'])
.fontSize(12)
.fontColor($r('app.color.app_color_text_tertiary'))
Blank()
Text(`浏览 ${app_guide['views']}`)
.fontSize(12)
.fontColor($r('app.color.app_color_text_tertiary'))
}
.width('100%')
}
.width('100%')
.padding(12)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
}
})
}
.width('100%')
.layoutWeight(1)
3.5 攻略信息展示
攻略列表项的布局结构:
┌─────────────────────────────────────────────────────────┐
│ │
│ 北京三日游攻略 │
│ │
│ 旅游达人 浏览 2.3万 │
│ │
└─────────────────────────────────────────────────────────┘
攻略信息的特点:
| 信息 | 说明 | 展示位置 |
|---|---|---|
| title | 攻略标题 | 顶部,加粗 |
| author | 作者 | 底部左侧 |
| views | 浏览量 | 底部右侧 |
3.6 作者信息展示
作者信息使用第三级文本样式:
Text(app_guide['author'])
.fontSize(12)
.fontColor($r('app.color.app_color_text_tertiary'))
作者展示的特点:
- 12号字体,较小
- 第三级文本色,不喧宾夺主
- 位于列表项底部左侧
3.7 浏览量展示
浏览量信息的展示:
Text(`浏览 ${app_guide['views']}`)
.fontSize(12)
.fontColor($r('app.color.app_color_text_tertiary'))
浏览量展示的特点:
- "浏览"前缀提供上下文
- 浏览量数字如"2.3万"简洁明了
- 位于列表项底部右侧
3.8 整体布局结构
旅游攻略应用的 UI 布局:
build() {
Column() {
CommonTitleBar({
app_title: '旅游攻略',
app_showBack: true
})
Column({ space: 16 }) {
// 标题行
Row({ space: 16 }) {
Column() { Text('热门目的地') }
Column() { Text('更多') }
}
// 加载按钮
Button('加载攻略')
// 攻略列表
List() {
ForEach(this.app_guides, ...)
}
.layoutWeight(1)
}
.width('100%')
.padding(16)
}
.backgroundColor($r('app.color.app_color_background'))
}
4. 内容展示设计
4.1 标题行设计模式
旅游攻略应用的标题行是内容类应用常见的 UI 模式:
Row({ space: 16 }) {
Column() {
Text('热门目的地')
}
.layoutWeight(1) // 左侧占据主要空间
Column() {
Text('更多')
}
}
标题行设计要点:
- Row 提供水平布局容器
- layoutWeight(1) 让左侧标题占据主要空间
- 右侧"更多"文字右对齐
- "更多"使用主题色,暗示可点击
4.2 列表项垂直布局
攻略列表项采用垂直布局:
Column({ space: 8 }) {
Text(app_guide['title']) // 标题在上
Row() { // 元信息在下
Text(app_guide['author'])
Blank()
Text(`浏览 ${app_guide['views']}`)
}
}
垂直布局的特点:
- Column 实现标题和元信息的垂直排列
- 标题占据整行宽度
- Row 实现作者和浏览量的水平排列
4.3 列表项样式设计
列表项使用卡片式设计:
Column({ space: 8 }) {
// 内容
}
.width('100%')
.padding(12)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
卡片样式特点:
- 白色背景与灰色页面背景形成对比
- 8vp 圆角提供柔和视觉效果
- 12vp 内边距提供舒适内容空间
4.4 内容排版设计
内容排版的要点:
Text(app_guide['title'])
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor($r('app.color.app_color_text_primary'))
.width('100%') // 标题占满宽度
宽度设置的作用:
- width(‘100%’) 确保标题占满整行
- 避免标题文字过长导致的布局问题
- 与下面的 Row 形成层次对比
5. UI 布局设计
5.1 布局容器层级
旅游攻略应用的布局容器层级:
| 层级 | 组件 | 作用 |
|---|---|---|
| 1 | Column | 根容器 |
| 2 | CommonTitleBar | 标题栏 |
| 2 | Column | 内容区域 |
| 3 | Row | 标题行 |
| 3 | Button | 加载按钮 |
| 3 | List | 攻略列表 |
| 4 | ForEach | 循环渲染 |
| 4 | ListItem | 列表项 |
| 5 | Column | 内容区 |
| 6 | Text | 标题 |
| 6 | Row | 元信息行 |
5.2 标题行布局设计
标题行的布局计算:
Row({ space: 16 }) {
Column() { Text('热门目的地') } // layoutWeight(1)
Column() { Text('更多') } // 无layoutWeight
}
布局结果:
- Row 总宽度 = 屏幕宽度 - 32vp(左右各16vp内边距)
- 左侧 Column 占据 (总宽度 - 16vp间距) × 1/1 = 主要空间
- 右侧 Column 占据自身内容宽度
5.3 列表项布局设计
列表项内部采用嵌套布局:
Column({ space: 8 }) { // 外层垂直布局
Text('标题') // 第一行:标题
Row() { // 第二行:元信息
Text('作者')
Blank()
Text('浏览量')
}
}
.width('100%')
.padding(12)
列表项布局层次:
| 层次 | 组件 | 内容 |
|---|---|---|
| 外层 | Column | 垂直排列 |
| 内层1 | Text | 攻略标题 |
| 内层2 | Row | 作者+浏览量 |
5.4 元信息行设计
元信息行使用水平布局:
Row() {
Text(app_guide['author']) // 左侧作者
Blank() // 中间填充
Text(`浏览 ${app_guide['views']}`) // 右侧浏览量
}
.width('100%')
元信息行的特点:
- 作者在左,浏览量在右
- Blank() 自动填充中间空间
- width(‘100%’) 确保占满列表项宽度
6. ArkTS 核心特性应用
6.1 @State 装饰器使用
旅游攻略应用只使用了一个 @State 变量:
@State app_guides: Record<string, string>[] = [];
单状态管理的特点:
- app_guides 存储攻略列表数据
- 点击加载按钮时更新此状态
- ForEach 监听到变化自动重新渲染
6.2 ForEach 组件使用
ForEach 组件的完整使用:
ForEach(this.app_guides, (app_guide: Record<string, string>) => {
ListItem() {
Column({ space: 8 }) {
Text(app_guide['title'])
Row() {
Text(app_guide['author'])
Blank()
Text(`浏览 ${app_guide['views']}`)
}
}
.padding(12)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
}
})
6.3 Record 类型数据访问
访问攻略 Record 数据的模式:
Text(app_guide['title']) // 攻略标题
Text(app_guide['author']) // 作者
Text(`浏览 ${app_guide['views']}`) // 浏览量
6.4 layoutWeight 布局
layoutWeight 在旅游攻略应用中的使用:
Row({ space: 16 }) {
Column() { Text('热门目的地') }
.layoutWeight(1) // 占据主要空间
Column() { Text('更多') }
// 无layoutWeight,靠右显示
}
7. 内容类应用开发要点
7.1 内容展示设计模式
旅游攻略应用的列表项是内容展示的典型模式:
┌─────────────────────────────────────────────────────────┐
│ │
│ [标题文字] │
│ │
│ [作者] [浏览量] │
│ │
└─────────────────────────────────────────────────────────┘
内容展示的要点:
- 标题醒目,位于顶部
- 作者和浏览量次要,位于底部
- 水平排列,左右分布
7.2 标题行设计模式
内容类应用常见的标题行模式:
Row({ space: 16 }) {
Text('主标题')
.fontWeight(FontWeight.Bold)
Blank()
Text('更多')
.fontColor($r('app.color.app_color_primary'))
}
标题行设计要点:
- 主标题在左,加粗
- 辅助操作在右,使用主题色
- Blank() 填充中间空间
7.3 卡片式设计
旅游攻略应用使用了卡片式列表项:
Column() {
// 内容
}
.padding(12)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
卡片式设计的优势:
- 白色背景与页面背景形成对比
- 圆角提供柔和视觉效果
- 内边距提供舒适的内容空间
7.4 内容排版要点
内容排版的技巧:
Text(app_guide['title'])
.width('100%') // 占满宽度
.width(‘100%’) 的作用:
- 确保标题占满整行
- 避免文字过长导致的布局问题
- 让布局更加可控
8. 扩展与展望
8.1 当前功能总结
旅游攻略应用实现了以下核心功能:
| 功能模块 | 实现描述 |
|---|---|
| 标题行 | 左侧主标题+右侧更多按钮 |
| 加载功能 | 点击按钮加载攻略数据 |
| 攻略展示 | 显示攻略标题、作者、浏览量 |
| 列表布局 | 垂直排列的卡片式列表项 |
8.2 功能扩展方向
基于当前的旅游攻略应用架构,可以进行以下功能扩展:
攻略详情页:点击攻略标题进入详情:
Text(app_guide['title'])
.onClick(() => {
// 跳转到详情页
})
分类标签:支持不同类型的攻略:
Row({ space: 8 }) {
Text('全部')
Text('美食')
Text('景点')
Text('住宿')
}
搜索功能:搜索攻略:
TextInput({ placeholder: '搜索攻略' })
.onChange((app_value) => {
this.app_searchText = app_value;
})
收藏功能:收藏攻略:
Button('收藏')
.onClick(() => {
// 收藏逻辑
})
分享功能:分享攻略:
Button('分享')
.onClick(() => {
// 分享逻辑
})
8.3 攻略数据模型扩展
扩展的攻略数据模型:
interface Guide {
id: string;
title: string;
author: string;
authorAvatar: string;
views: string;
likes: string;
coverImage: string;
summary: string;
publishDate: string;
tags: string[];
}
8.4 实际API对接
实际项目中的攻略 API 对接:
interface GuideListParams {
category?: string;
keyword?: string;
page: number;
pageSize: number;
}
async function getGuides(params: GuideListParams): Promise<Record<string, string>[]> {
// 实际项目中调用真实API
// const response = await fetch(`/api/guides?category=${params.category}&keyword=${params.keyword}`);
// return response.json();
return [
{ 'title': '北京三日游攻略', 'author': '旅游达人', 'views': '2.3万' }
];
}
9. 技术要点总结
9.1 核心代码模块
旅游攻略应用的代码结构:
@Entry
@Component
struct TravelGuide {
@State app_guides: Record<string, string>[] = [];
build() {
Column() {
CommonTitleBar({ app_title: '旅游攻略', app_showBack: true })
Column({ space: 16 }) {
// 标题行
Row({ space: 16 }) {
Column() {
Text('热门目的地')
.fontWeight(FontWeight.Bold)
}
.layoutWeight(1)
Column() {
Text('更多')
.fontColor($r('app.color.app_color_primary'))
}
}
// 加载按钮
Button('加载攻略')
.onClick(() => {
this.app_guides = [
{ 'title': '北京三日游攻略', 'author': '旅游达人', 'views': '2.3万' },
{ 'title': '上海迪士尼游玩指南', 'author': '小可爱', 'views': '1.8万' },
{ 'title': '成都美食攻略', 'author': '吃货一枚', 'views': '3.5万' },
{ 'title': '杭州西湖游览路线', 'author': '风景摄影', 'views': '1.2万' }
];
})
// 攻略列表
List() {
ForEach(this.app_guides, (app_guide) => {
ListItem() { ... }
})
}
.layoutWeight(1)
}
.padding(16)
}
.backgroundColor($r('app.color.app_color_background'))
}
}
9.2 关键技术点
| 技术点 | 在本应用中的体现 |
|---|---|
| Row组件 | 标题行、作者浏览量行 |
| Column组件 | 列表项、标题行分区 |
| layoutWeight | 标题行左侧占据主要空间 |
| Text组件 | 标题、作者、浏览量 |
| Button组件 | 加载攻略操作 |
| List组件 | 攻略列表容器 |
| ForEach组件 | 遍历渲染攻略 |
| Record类型 | 攻略数据结构 |
| Blank组件 | 填充中间空间 |
9.3 布局模式总结
旅游攻略应用的布局模式:
┌─────────────────────────────────────────────────────────┐
│ 根Column │
│ ├── CommonTitleBar │
│ └── 内容Column │
│ ├── 标题行Row │
│ │ ├── Column(主标题, layoutWeight(1)) │
│ │ └── Column(更多) │
│ ├── Button(加载攻略) │
│ └── List │
│ └── ForEach │
│ └── ListItem │
│ └── Column │
│ ├── Text(标题) │
│ └── Row │
│ ├── Text(作者) │
│ ├── Blank │
│ └── Text(浏览量) │
└─────────────────────────────────────────────────────────┘
10. 完整代码结构
import { CommonTitleBar } from '../../components/CommonTitleBar';
@Entry
@Component
struct TravelGuide {
@State app_guides: Record<string, string>[] = [];
build() {
Column() {
CommonTitleBar({
app_title: '旅游攻略',
app_showBack: true
})
Column({ space: 16 }) {
Row({ space: 16 }) {
Column() {
Text('热门目的地')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.app_color_text_primary'))
}
.layoutWeight(1)
Column() {
Text('更多')
.fontSize(14)
.fontColor($r('app.color.app_color_primary'))
}
}
Button('加载攻略')
.width('100%')
.onClick(() => {
this.app_guides = [
{ 'title': '北京三日游攻略', 'author': '旅游达人', 'views': '2.3万' },
{ 'title': '上海迪士尼游玩指南', 'author': '小可爱', 'views': '1.8万' },
{ 'title': '成都美食攻略', 'author': '吃货一枚', 'views': '3.5万' },
{ 'title': '杭州西湖游览路线', 'author': '风景摄影', 'views': '1.2万' }
];
})
List() {
ForEach(this.app_guides, (app_guide: Record<string, string>) => {
ListItem() {
Column({ space: 8 }) {
Text(app_guide['title'])
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor($r('app.color.app_color_text_primary'))
.width('100%')
Row() {
Text(app_guide['author'])
.fontSize(12)
.fontColor($r('app.color.app_color_text_tertiary'))
Blank()
Text(`浏览 ${app_guide['views']}`)
.fontSize(12)
.fontColor($r('app.color.app_color_text_tertiary'))
}
.width('100%')
}
.width('100%')
.padding(12)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
}
})
}
.width('100%')
.layoutWeight(1)
}
.width('100%')
.padding(16)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.app_color_background'))
}
}
11. 结语
旅游攻略应用作为一款内容展示类应用,展示了 HarmonyOS ArkUI 框架在内容资讯类应用开发方面的核心能力。通过 Row、Column、List、ForEach 等组件的组合使用,实现了标题行和攻略列表的完整展示。
从技术角度来看,应用的核心亮点在于标题行设计和垂直布局的列表项。Row 配合 layoutWeight 实现了左侧主标题右侧辅助操作的布局,Column 的垂直嵌套实现了标题和元信息的层次展示。
从应用设计的角度来看,旅游攻略应用遵循了"内容为主、操作为辅"的设计原则。攻略标题醒目展示,作者和浏览量作为元信息次要展示。标题行设计提供了分类导航的入口,虽然当前实现是静态的,但已经展示了内容类应用的典型 UI 形态。
与之前的出行预订类应用相比,旅游攻略应用更注重内容本身而非价格和预订操作。这种差异反映了不同业务场景的需求:出行预订强调价格和操作,而内容展示强调标题和作者信息。
更多推荐



所有评论(0)