HarmonyOS应用<节气通>开发第22篇:HolidayCard组件封装

引言

节日卡片组件是展示节日信息的重要UI元素。本文将介绍如何封装一个HolidayCard组件,用于展示节日和节气信息。通过组件封装,可以:

  • 统一节日展示风格
  • 支持不同类型节日
  • 显示日期高亮
  • 提供节日详情入口

通过本文,你将掌握如何封装高质量的节日卡片组件。


学习目标

完成本文后,你将能够:

  • ✅ 理解节日卡片组件的设计原则
  • ✅ 封装HolidayCard组件
  • ✅ 添加节日类型标识
  • ✅ 实现日期高亮显示
  • ✅ 处理点击事件

需求分析

组件功能设计

功能 描述 技术要点
节日图标 展示节日图标 Image组件
节日名称 展示节日名称 Text组件
日期信息 展示日期 Text组件
节日类型 标识节日类型 颜色区分
背景图片 根据节日类型显示背景 Image组件
点击事件 跳转到详情页 路由跳转

核心实现

步骤1: 组件接口定义

typescript 复制代码
// components/HolidayCard.ets

/**
 * 节日卡片组件
 */
@Component
export struct HolidayCard {
  // 节日ID
  @Prop id: string = '';
  
  // 节日名称
  @Prop name: string = '';
  
  // 日期(格式:MM月DD日)
  @Prop date: string = '';
  
  // 农历日期
  @Prop lunarDate: string = '';
  
  // 节日类型
  @Prop type: HolidayType = 'solar';
  
  // 背景图片
  @Prop background: string = '';
  
  // 点击事件
  @Prop onClick: () => void = () => {};
  
  /**
   * 获取节日类型配置
   */
  private getTypeConfig(): TypeConfig {
    const configs: Record<HolidayType, TypeConfig> = {
      solar: {
        label: '节气',
        labelColor: '#4A9B6D',
        backgroundColor: '#E8F5E9',
        borderColor: '#4A9B6D'
      },
      lunar: {
        label: '农历',
        labelColor: '#FF5722',
        backgroundColor: '#FFF8E1',
        borderColor: '#FF5722'
      },
      holiday: {
        label: '节日',
        labelColor: '#E91E63',
        backgroundColor: '#FCE4EC',
        borderColor: '#E91E63'
      },
      solarTerm: {
        label: '节气',
        labelColor: '#00BCD4',
        backgroundColor: '#E1F5FE',
        borderColor: '#00BCD4'
      }
    };
    
    return configs[this.type] || configs.solar;
  }
  
  /**
   * 构建UI
   */
  build() {
    const config = this.getTypeConfig();
    
    Card() {
      Stack({ alignContent: Alignment.BottomStart }) {
        // 背景图片
        Image(this.background || $r('app.media.ic_default_bg'))
          .width('100%')
          .height(120)
          .objectFit(ImageFit.Cover)
        
        // 渐变遮罩
        Row()
          .width('100%')
          .height(120)
          .linearGradient({
            angle: 180,
            colors: [
              ['#00000000', 0.3],
              ['#000000CC', 1]
            ]
          })
        
        // 内容
        Column({ space: 4 }) {
          // 类型标签
          Text(config.label)
            .fontSize(11)
            .fontColor(config.labelColor)
            .padding({ left: 8, right: 8, top: 2, bottom: 2 })
            .backgroundColor('#FFFFFF')
            .borderRadius(4)
            .opacity(0.9)
          
          // 节日名称
          Text(this.name)
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor('#FFFFFF')
          
          // 日期信息
          Row({ space: 8 }) {
            Text(this.date)
              .fontSize(14)
              .fontColor('#FFFFFF')
              .opacity(0.8)
            
            if (this.lunarDate) {
              Text(this.lunarDate)
                .fontSize(14)
                .fontColor('#FFFFFF')
                .opacity(0.8)
            }
          }
        }
        .padding(12)
      }
    }
    .width('100%')
    .onClick(() => {
      this.onClick();
    })
  }
}

type HolidayType = 'solar' | 'lunar' | 'holiday' | 'solarTerm';

interface TypeConfig {
  label: string;
  labelColor: string;
  backgroundColor: string;
  borderColor: string;
}

设计要点:

  • 支持多种节日类型
  • 背景图片+渐变遮罩
  • 类型标签标识

步骤2: 日历视图中的节日卡片

typescript 复制代码
/**
 * 日历视图中的节日卡片(小尺寸)
 */
@Component
export struct HolidayCardMini {
  @Prop holiday: Holiday = {} as Holiday;
  @Prop isToday: boolean = false;
  @Prop onClick: () => void = () => {};
  
  build() {
    const config = this.getTypeConfig(this.holiday.type);
    
    Column({ space: 4 }) {
      // 日期数字
      Stack({ alignContent: Alignment.Center }) {
        if (this.isToday) {
          Circle()
            .width(32)
            .height(32)
            .fillColor('#4A9B6D')
          
          Text(this.holiday.day)
            .fontSize(14)
            .fontWeight(FontWeight.Bold)
            .fontColor('#FFFFFF')
        } else {
          Text(this.holiday.day)
            .fontSize(14)
            .fontColor('#333333')
        }
      }
      
      // 节日名称(简短)
      if (this.holiday.name) {
        Text(this.holiday.name.slice(0, 2))
          .fontSize(10)
          .fontColor(config.labelColor)
      }
      
      // 类型标识点
      Circle()
        .width(4)
        .height(4)
        .fillColor(config.labelColor)
    }
    .width('100%')
    .alignItems(HorizontalAlign.Center)
    .padding(4)
    .onClick(() => {
      this.onClick();
    })
  }
  
  private getTypeConfig(type: HolidayType): TypeConfig {
    const configs: Record<HolidayType, TypeConfig> = {
      solar: { label: '', labelColor: '#4A9B6D', backgroundColor: '', borderColor: '' },
      lunar: { label: '', labelColor: '#FF5722', backgroundColor: '', borderColor: '' },
      holiday: { label: '', labelColor: '#E91E63', backgroundColor: '', borderColor: '' },
      solarTerm: { label: '', labelColor: '#00BCD4', backgroundColor: '', borderColor: '' }
    };
    return configs[type] || configs.solar;
  }
}

interface Holiday {
  id: string;
  name: string;
  day: string;
  date: string;
  lunarDate?: string;
  type: HolidayType;
  background?: string;
}

设计要点:

  • 小尺寸卡片,适合日历视图
  • 日期高亮显示(当天)
  • 节日名称缩写
  • 类型颜色标识

步骤3: 使用HolidayCard组件

typescript 复制代码
// 在页面中使用HolidayCard组件

@Entry
@Component
struct HolidayPage {
  @State holidays: Holiday[] = [
    {
      id: '1',
      name: '立春',
      day: '04',
      date: '02月04日',
      lunarDate: '正月十四',
      type: 'solarTerm',
      background: 'https://example.com/spring.jpg'
    },
    {
      id: '2',
      name: '春节',
      day: '10',
      date: '02月10日',
      lunarDate: '正月初一',
      type: 'holiday',
      background: 'https://example.com/spring_festival.jpg'
    },
    {
      id: '3',
      name: '元宵节',
      day: '24',
      date: '02月24日',
      lunarDate: '正月十五',
      type: 'lunar',
      background: 'https://example.com/lantern.jpg'
    }
  ];
  
  build() {
    List({ space: 12 }) {
      ForEach(this.holidays, (holiday: Holiday) => {
        ListItem() {
          HolidayCard({
            id: holiday.id,
            name: holiday.name,
            date: holiday.date,
            lunarDate: holiday.lunarDate,
            type: holiday.type,
            background: holiday.background,
            onClick: () => {
              // 跳转到节日详情页
              router.pushUrl({ url: 'pages/HolidayDetail', params: { id: holiday.id } });
            }
          })
        }
      }, (holiday: Holiday) => holiday.id)
    }
    .width('92%')
    .padding({ top: 12 })
  }
}

设计要点:

  • 在List中使用HolidayCard
  • 绑定数据和事件
  • 跳转到详情页

步骤4: 横向滚动节日卡片

typescript 复制代码
/**
 * 横向滚动节日卡片
 */
@Component
export struct HolidayCardHorizontal {
  @Prop holiday: Holiday = {} as Holiday;
  @Prop onClick: () => void = () => {};
  
  build() {
    const config = this.getTypeConfig(this.holiday.type);
    
    Card() {
      Column({ space: 8 }) {
        // 日期区域
        Stack({ alignContent: Alignment.Center }) {
          Circle()
            .width(56)
            .height(56)
            .fillColor(config.backgroundColor)
          
          Column({ space: 2 }) {
            Text(this.holiday.date.split('月')[0])
              .fontSize(18)
              .fontWeight(FontWeight.Bold)
              .fontColor(config.labelColor)
            
            Text('月')
              .fontSize(10)
              .fontColor(config.labelColor)
          }
        }
        
        // 节日名称
        Text(this.holiday.name)
          .fontSize(15)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
        
        // 农历日期
        if (this.holiday.lunarDate) {
          Text(this.holiday.lunarDate)
            .fontSize(12)
            .fontColor('#999999')
        }
        
        // 类型标签
        Text(config.label)
          .fontSize(11)
          .fontColor(config.labelColor)
          .padding({ left: 8, right: 8, top: 2, bottom: 2 })
          .backgroundColor(config.backgroundColor)
          .borderRadius(4)
      }
      .width(80)
      .padding(12)
      .alignItems(HorizontalAlign.Center)
    }
    .onClick(() => {
      this.onClick();
    })
  }
  
  private getTypeConfig(type: HolidayType): TypeConfig {
    const configs: Record<HolidayType, TypeConfig> = {
      solar: { label: '节气', labelColor: '#4A9B6D', backgroundColor: '#E8F5E9', borderColor: '' },
      lunar: { label: '农历', labelColor: '#FF5722', backgroundColor: '#FFF8E1', borderColor: '' },
      holiday: { label: '节日', labelColor: '#E91E63', backgroundColor: '#FCE4EC', borderColor: '' },
      solarTerm: { label: '节气', labelColor: '#00BCD4', backgroundColor: '#E1F5FE', borderColor: '' }
    };
    return configs[type] || configs.solar;
  }
}

设计要点:

  • 横向滚动布局
  • 圆形日期展示
  • 类型标签

本章小结

核心知识点

本文完成了HolidayCard组件的封装:

1. 组件属性设计

  • id: 节日ID
  • name: 节日名称
  • date: 日期
  • lunarDate: 农历日期
  • type: 节日类型
  • background: 背景图片
  • onClick: 点击事件

2. 节日类型支持

  • solar: 阳历节日
  • lunar: 农历节日
  • holiday: 法定节日
  • solarTerm: 节气

3. 组件变体

  • HolidayCard: 标准卡片,带背景图
  • HolidayCardMini: 小尺寸卡片,适合日历
  • HolidayCardHorizontal: 横向滚动卡片

下一步预告

HolidayCard组件已经完成!在下一篇文章中,我们将学习:

  • Timeline时间线组件封装
  • 时间线布局
  • 节点展示
  • 事件标记

节气通应用已发布上线,可在应用市场下载体验


相关链接

相关推荐
芒鸽1 小时前
HarmonyOS ArkUI 组件开发实战:自定义组件与高级布局详解
华为·harmonyos
IT大白鼠2 小时前
BGP多归属技术原理与应用实践
网络·网络协议·华为
祭曦念2 小时前
鸿蒙Next实战-笑话大全App开发
华为·harmonyos
三声三视2 小时前
Electron 鸿蒙快捷键全失灵,我排查了六个小时
华为·electron·harmonyos·鸿蒙
风华圆舞2 小时前
鸿蒙构建失败时,先查 Flutter 还是先查 Hvigor
flutter·华为·harmonyos
YM52e2 小时前
鸿蒙HarmonyOS ArkTS 实战:教师座椅出入记录 APP 从零到一
学习·华为·harmonyos·鸿蒙系统
狼哥16862 小时前
蛋糕美食元服务_订单实现指南
ui·harmonyos
Swift社区2 小时前
鸿蒙游戏如何实现多端一致性?
游戏·华为·harmonyos
木咺吟2 小时前
【鸿蒙原生应用开发实战】第一篇:项目初始化与架构设计——从零搭建“阅迹“阅读应用
华为·harmonyos