在这里插入图片描述
在这里插入图片描述

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 形态。

与之前的出行预订类应用相比,旅游攻略应用更注重内容本身而非价格和预订操作。这种差异反映了不同业务场景的需求:出行预订强调价格和操作,而内容展示强调标题和作者信息。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐