HarmonyOS ArkTS 实战:实现一个校园二手物品交易应用

项目效果

本文使用 HarmonyOS 和 ArkTS 实现一个校园二手物品交易应用。

应用可以发布二手物品信息,设置物品价格和新旧程度,浏览商品列表,联系卖家,标记物品已售出,并提供分类筛选、价格排序和收藏等功能。

项目使用 DevEco Studio 开发,适配 API 23 及以上版本。

功能介绍

本项目实现了以下功能:

  • 发布二手物品信息
  • 填写物品名称和详细描述
  • 设置物品价格
  • 选择物品分类
  • 选择新旧程度
  • 留下卖家联系方式
  • 标记物品已售出
  • 收藏感兴趣的物品
  • 按分类和状态筛选物品
  • 按价格排序
  • 统计在售、已售和收藏数量
  • 删除已下架的物品

定义数据结构

首先定义二手商品的数据结构:

interface SecondHandItem {
  id: number;
  title: string;
  description: string;
  price: number;
  originalPrice: number;
  category: string;
  condition: string;
  seller: string;
  contact: string;
  status: string;
  isCollected: boolean;
  publishTime: string;
}

字段说明如下:

  • id:商品的唯一编号
  • title:物品标题
  • description:物品详细描述
  • price:出售价格
  • originalPrice:原价
  • category:物品分类
  • condition:新旧程度
  • seller:卖家姓名
  • contact:联系方式
  • status:商品状态(在售/已售出)
  • isCollected:是否已收藏
  • publishTime:发布时间

初始化页面状态

使用 @State 保存输入内容、分类选择、筛选条件和排序方式:

@State private titleText: string = '';
@State private descriptionText: string = '';
@State private priceText: string = '';
@State private originalPriceText: string = '';
@State private contactText: string = '';
@State private sellerText: string = '';
@State private category: string = '数码产品';
@State private condition: string = '九成新';
@State private filterType: string = '全部';
@State private sortType: string = '默认';
@State private nextId: number = 6;

准备一些初始数据,让应用运行后可以直接展示完整效果:

@State private items: SecondHandItem[] = [
  {
    id: 1,
    title: 'iPad Air 4 64G 银色',
    description: '自用一年,无磕碰,带原装充电器和保护套',
    price: 2200,
    originalPrice: 4799,
    category: '数码产品',
    condition: '九成新',
    seller: '陈同学',
    contact: '微信:chen2026',
    status: '在售',
    isCollected: false,
    publishTime: '2026-07-15'
  },
  {
    id: 2,
    title: '高等数学同济第七版',
    description: '上下册两本,有少量笔记,不影响使用',
    price: 15,
    originalPrice: 80,
    category: '书籍教材',
    condition: '八成新',
    seller: '刘同学',
    contact: 'QQ:123456789',
    status: '在售',
    isCollected: true,
    publishTime: '2026-07-16'
  },
  {
    id: 3,
    title: '捷安特山地车',
    description: 'ATX660,骑了两年,刹车刚换过',
    price: 450,
    originalPrice: 1298,
    category: '生活用品',
    condition: '七成新',
    seller: '周同学',
    contact: '电话:139****1234',
    status: '已售出',
    isCollected: false,
    publishTime: '2026-07-10'
  },
  {
    id: 4,
    title: '罗技G304无线鼠标',
    description: '白色,用了三个月,包装齐全',
    price: 120,
    originalPrice: 229,
    category: '数码产品',
    condition: '九五新',
    seller: '吴同学',
    contact: '微信:wuxiaoming',
    status: '在售',
    isCollected: false,
    publishTime: '2026-07-17'
  }
];

发布二手物品

用户填写物品信息后,可以发布新的二手商品:

private addItem(): void {
  const title: string = this.titleText.trim();
  const price: number = parseInt(this.priceText);
  const seller: string = this.sellerText.trim();
  const contact: string = this.contactText.trim();

  if (title.length === 0 || isNaN(price) || seller.length === 0 || contact.length === 0) {
    return;
  }

  const originalPrice: number = this.originalPriceText ? parseInt(this.originalPriceText) : price * 2;
  const today = new Date();
  const dateStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;

  const item: SecondHandItem = {
    id: this.nextId,
    title,
    description: this.descriptionText.trim(),
    price,
    originalPrice,
    category: this.category,
    condition: this.condition,
    seller,
    contact,
    status: '在售',
    isCollected: false,
    publishTime: dateStr
  };

  this.items = [item, ...this.items];
  this.nextId += 1;
  this.titleText = '';
  this.descriptionText = '';
  this.priceText = '';
  this.originalPriceText = '';
  this.sellerText = '';
  this.contactText = '';
}

新发布的物品默认处于"在售"状态。

商品状态流转

二手商品按照以下流程处理:

在售 -> 已售出

使用以下方法更新商品状态:

private markAsSold(id: number): void {
  this.items = this.items.map((item: SecondHandItem) => {
    if (item.id === id) {
      return {
        id: item.id,
        title: item.title,
        description: item.description,
        price: item.price,
        originalPrice: item.originalPrice,
        category: item.category,
        condition: item.condition,
        seller: item.seller,
        contact: item.contact,
        status: '已售出',
        isCollected: item.isCollected,
        publishTime: item.publishTime
      };
    }
    return item;
  });
}

在售状态点击"标记已售"后变为已售出状态。

收藏与取消收藏

用户可以收藏感兴趣的物品:

private toggleCollect(id: number): void {
  this.items = this.items.map((item: SecondHandItem) => {
    if (item.id === id) {
      return {
        id: item.id,
        title: item.title,
        description: item.description,
        price: item.price,
        originalPrice: item.originalPrice,
        category: item.category,
        condition: item.condition,
        seller: item.seller,
        contact: item.contact,
        status: item.status,
        isCollected: !item.isCollected,
        publishTime: item.publishTime
      };
    }
    return item;
  });
}

点击收藏按钮可以切换收藏状态。

筛选和排序物品

页面支持按照分类和状态筛选,并支持价格排序:

private getFilteredItems(): SecondHandItem[] {
  let result = [...this.items];
  
  if (this.filterType === '在售') {
    result = result.filter((item: SecondHandItem) => item.status === '在售');
  } else if (this.filterType === '已售出') {
    result = result.filter((item: SecondHandItem) => item.status === '已售出');
  } else if (this.filterType === '我的收藏') {
    result = result.filter((item: SecondHandItem) => item.isCollected);
  } else if (this.filterType !== '全部') {
    result = result.filter((item: SecondHandItem) => item.category === this.filterType);
  }

  if (this.sortType === '价格从低到高') {
    result.sort((a, b) => a.price - b.price);
  } else if (this.sortType === '价格从高到低') {
    result.sort((a, b) => b.price - a.price);
  }

  return result;
}

筛选按钮封装如下:

@Builder
FilterButton(text: string) {
  Button(text)
    .height(32)
    .padding({ left: 12, right: 12 })
    .fontSize(12)
    .fontColor(this.filterType === text ? Color.White : '#344054')
    .backgroundColor(
      this.filterType === text ? '#EA580C' : '#FFF7ED'
    )
    .borderRadius(16)
    .onClick(() => {
      this.filterType = text;
    });
}

选择新旧程度

页面支持多种新旧程度选择:

@Builder
ConditionButton(text: string) {
  Button(text)
    .height(34)
    .layoutWeight(1)
    .fontSize(12)
    .fontColor(this.condition === text ? Color.White : '#344054')
    .backgroundColor(
      this.condition === text ? '#EA580C' : '#F3F4F6'
    )
    .borderRadius(8)
    .onClick(() => {
      this.condition = text;
    });
}

不同新旧程度使用橙色主题色高亮显示。

统计商品数据

使用 filter 统计各类商品数量:

private getCount(filter: string): number {
  if (filter === '在售') {
    return this.items.filter((item: SecondHandItem) => item.status === '在售').length;
  }
  if (filter === '已售出') {
    return this.items.filter((item: SecondHandItem) => item.status === '已售出').length;
  }
  if (filter === '收藏') {
    return this.items.filter((item: SecondHandItem) => item.isCollected).length;
  }
  return this.items.length;
}

顶部统计区域展示全部商品、在售、已售出和收藏数量:

this.StatCard(
  '全部商品',
  `${this.getCount('全部')}`,
  '#EA580C',
  '#FFF7ED'
);
this.StatCard(
  '正在出售',
  `${this.getCount('在售')}`,
  '#059669',
  '#ECFDF5'
);
this.StatCard(
  '我的收藏',
  `${this.getCount('收藏')}`,
  '#DC2626',
  '#FEF2F2'
);

设置状态颜色

不同商品状态使用不同颜色:

private getStatusColor(status: string): ResourceColor {
  if (status === '在售') {
    return '#059669';
  }
  return '#6B7280';
}

private getConditionColor(condition: string): ResourceColor {
  if (condition === '全新' || condition === '九五新') {
    return '#059669';
  }
  if (condition === '九成新' || condition === '八成新') {
    return '#D97706';
  }
  return '#DC2626';
}

颜色含义如下:

  • 绿色:在售/成色较新
  • 橙色:成色一般
  • 红色:成色较旧/收藏
  • 橙色:页面主题色

删除商品记录

已下架或过期的商品可以删除:

private deleteItem(id: number): void {
  this.items = this.items.filter(
    (item: SecondHandItem) => item.id !== id
  );
}

删除后,商品列表和顶部统计数据会自动更新。

使用列表展示商品

使用 ListForEach 渲染筛选后的商品:

List({ space: 12 }) {
  ForEach(
    this.getFilteredItems(),
    (item: SecondHandItem) => {
      ListItem() {
        this.ItemCard(item)
      }
    },
    (item: SecondHandItem) => item.id.toString()
  );
}
.width('100%')
.layoutWeight(1)
.scrollBar(BarState.Off);

每件商品使用独立卡片展示,卡片中包含标题、描述、价格、原价、分类、成色、卖家信息、状态和操作按钮。

页面设计说明

应用使用橙色作为主题色,适合二手交易活泼热闹的氛围。

页面主要分为以下区域:

  1. 顶部标题和今日新上架数量
  2. 商品数据统计区域
  3. 发布二手物品表单
  4. 分类筛选和排序区域
  5. 二手商品列表

页面采用浅灰色背景和白色卡片。在售商品使用绿色标识,已售出使用灰色标识,价格使用大号橙色字体突出显示,便于快速浏览。

SDK 配置

本项目使用 HarmonyOS API 24,满足 API 23 及以上要求:

{
  "name": "default",
  "compatibleSdkVersion": "6.1.1(24)",
  "runtimeOS": "HarmonyOS",
  "targetSdkVersion": "6.1.1(24)",
  "compileSdkVersion": "6.1.1(24)"
}

entry 模块中的运行系统也要保持一致:

{
  "apiType": "stageMode",
  "targets": [
    {
      "name": "default",
      "runtimeOS": "HarmonyOS"
    }
  ]
}

运行项目

使用 DevEco Studio 打开项目,然后找到:

entry/src/main/ets/pages/Index.ets

等待项目同步完成,点击右侧的 Preview 按钮即可查看应用效果。

项目总结

本文使用 HarmonyOS 和 ArkTS 实现了一个校园二手物品交易应用。

项目实现了商品发布、价格设置、分类选择、成色选择、联系方式、标记已售、收藏功能、分类筛选、价格排序、数据统计和删除等功能。

通过这个项目可以掌握:

  • ArkTS 接口定义
  • @State 状态管理
  • 数字输入和价格处理
  • ListForEach 列表渲染
  • mapfilter 数组操作
  • 多条件筛选和排序
  • 收藏状态切换
  • 自定义 @Builder 组件
  • HarmonyOS 商品卡片布局

后续还可以加入商品图片上传、聊天功能、议价功能、同城面交定位、信用评价系统、搜索功能和交易担保等功能。

Logo

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

更多推荐