HarmonyOS 鸿蒙Next 想实现点击后改变样式

发布于 1周前 作者 h691938207 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 想实现点击后改变样式

自己封装了一个日历组件,现在想实现像手机日历那样,点击到哪天哪天就亮一下,不知道onclick中怎么修改样式,附上代码:

@Entry
@Component
export default struct CalendarItem {
  //定义当年当月当日
  @State currentYear: number = 2024
  @State currentMonth: number = 0
  @State currentDay: number = 0
  //日历第一天 为1:周日 为0: 周一
  //取得当月天数
  @State allDay: number[] = []
  //获取当月第一天是星期几
  @State currentFirstWeekDay: number = 1
  @State week: string[] = ['日', '一', '二', '三', '四', '五', '六']
  //存放上个月的天数
  @State preMonth: any[] = []
  //需要显示下月的天数
  @State nextMonth: any[] = []
  //当前
  @State currentText: string = ''
  //监听
  private onClickItem: (string) => void;
//获取上月天数
  getPrevMonthDay() {
    let date = new Date(this.currentYear, this.currentMonth - 1, 0); // 获取上月;
    let day = date.getDate(); // 因为Date函数中天设置的0,因此这里是上月最后一天的值
    let days = this.currentFirstWeekDay; // 上月要显示几天
    let weeks = [];
    while (days > 0) {
      weeks.push({
        year: date.getFullYear(),
        month: date.getMonth() + 1,
        day: day--,
      });
      days--;
    }
    return weeks.sort((a, b) => a.day - b.day); // 因为是从大到小的,排个序
  }
//获取下月天数
  getNextMonthDay(){
    let date = new Date(this.currentYear, this.currentMonth - 1, 0); // 获取上月;
    let day = date.getDate(); // 因为Date函数中天设置的0,因此这里是上月最后一天的值
    let days = this.currentFirstWeekDay; // 上月要显示几天
    let weeks = [];
    while (days > 0) {
      weeks.push({
        year: date.getFullYear(),
        month: date.getMonth() + 1,
        day: day--,
      });
      days--;
    }
    return weeks.sort((a, b) => a.day - b.day); // 因为是从大到小的,排个序
  }

  aboutToAppear() {
    let date = new Date();
    this.currentDay = date.getDate()
    this.currentMonth = date.getMonth() + 1;
    this.currentYear = date.getFullYear();
    this.currentFirstWeekDay = new Date(date.getFullYear(), date.getMonth(), 1).getDay();
    let allDay = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();

    for (let i = 0;i < allDay; i++) {

      this.allDay[i] = i
    }
    this.preMonth = this.getPrevMonthDay()
  }
  refreshDays(month: number,year: number){
    //上月
    let date = new Date(year, month - 1, 0); // 获取上月;
    let day = date.getDate(); // 因为Date函数中天设置的0,因此这里是上月最后一天的值
    this.currentFirstWeekDay = new Date(year, month-1, 1).getDay();
    let days = this.currentFirstWeekDay; // 上月要显示几天
    let weeks = [];
    while (days > 0) {
      weeks.push({
        day: day--,
      });
      days--;
    }
    weeks.sort((a, b) => a.day - b.day); // 因为是从大到小的,排个序
    this.preMonth = weeks
    //本月
    console.info(`year${year}month${month}`)
    let allDay = new Date(year, month, 0).getDate();
    console.info(`allDay${allDay}`)
    //需要先重置
    this.allDay = []
    for (let i = 0;i < allDay; i++) {
      this.allDay[i] = i
    }
    console.info(`${this.allDay}`)
  }
  refreshDate(month: number) {
    if (month < 1) {
      this.currentMonth = 12
      this.currentYear--
      //重新更新天数
      this.refreshDays(this.currentMonth,this.currentYear)
    }
    else if (month > 12) {
      this.currentMonth = 1
      this.currentYear++

      this.refreshDays(this.currentMonth,this.currentYear)
    }
    else {
      this.currentMonth = month
      this.currentYear = this.currentYear;

      this.refreshDays(this.currentMonth,this.currentYear)
    }
  }

  @Builder Header() {
    Row() {
      Image($rawfile('icon_arrow_l.svg'))
        .width(15)
        .height(15)
        .margin({ right: 20 })
        .onClick(() => {
          this.currentMonth--
          this.refreshDate(this.currentMonth)
        })
      Text(`${this.currentYear}年${this.currentMonth}月`)
        .fontSize(20)
      Image($rawfile('icon_arrow_r.svg'))
        .width(15)
        .height(15)
        .margin({ left: 20 })
        .onClick(() => {
          this.currentMonth++

          this.refreshDate(this.currentMonth)
        })
    }
  }

  @Builder Week(value: string[]) {
    Column() {
      Grid() {
        ForEach(value, (data: string) => {
          GridItem() {
            Text(data)
              .fontSize(16)
              .fontWeight(FontWeight.Bold)
              .width('100%')
              .textAlign(TextAlign.Center)
          }
        })
      }
      .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
      .columnsGap(10)
      .rowsGap(10)
      .width('90%')
      .height(50)
    }
    .width('100%')
    .margin({ bottom: 10 })
  }

  @Builder Day() {
    Grid() {
      ForEach(this.preMonth, (i) => {
        GridItem() {
          Text(String(i['day']))
            .textAlign(TextAlign.Center)
            .fontSize(16)
            .fontColor(Color.Gray)
        }
        .onClick(() => {
          this.currentMonth--
          console.info(`currentMonth${this.currentMonth}`)
          this.refreshDate(this.currentMonth)
        })
      })
      ForEach(this.allDay, (i) => {
        GridItem() {
            Text(String(i + 1))
              .fontSize(16)
              .fontColor('#ff2e5391')
              .textAlign(TextAlign.Center)
              .onClick(()=> {
                this.onClickItem(this.currentYear + "-" + this.currentMonth + "-" + (i+1))

              })
        }
      })
    }
    .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
    .columnsGap(10)
    .rowsGap(10)
    .width('90%')

  }
  build() {
    Column() {
      this.Header()
      this.Week(this.week)
      this.Day()
    }
  }
}

更多关于HarmonyOS 鸿蒙Next 想实现点击后改变样式的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

15 回复

加个isSelect下标就行了

class MyDate {
  year: number
  month: number
  day: number

  constructor(year: number, month: number, day: number) {
    this.year = year;
    this.month = month;
    this.day = day
  }
}

export default struct CalendarItem {
  @State isSelectIndex: number = -1
  //定义当年当月当日
  @State currentYear: number = 2024
  @State currentMonth: number = 0
  @State currentDay: number = 0
  //日历第一天 为1:周日 为0: 周一
  //取得当月天数
  @State allDay: number[] = []
  //获取当月第一天是星期几
  @State currentFirstWeekDay: number = 1
  @State week: string[] = ['日', '一', '二', '三', '四', '五', '六']
  //存放上个月的天数
  @State preMonth: MyDate[] = []
  //需要显示下月的天数
  @State nextMonth: MyDate[] = []
  //当前
  @State currentText: string = ''

  //获取上月天数
  getPrevMonthDay() {
    let date = new Date(this.currentYear, this.currentMonth - 1, 0); // 获取上月;
    let day = date.getDate(); // 因为Date函数中天设置的0,因此这里是上月最后一天的值
    let days = this.currentFirstWeekDay; // 上月要显示几天
    let weeks: MyDate[] = [];
    while (days > 0) {
      weeks.push(new MyDate(date.getFullYear(), date.getMonth() + 1, day--));
      days--;
    }
    return weeks.sort((a: MyDate, b: MyDate) => a.day - b.day); // 因为是从大到小的,排个序
  }

  //获取下月天数
  getNextMonthDay() {
    let date = new Date(this.currentYear, this.currentMonth - 1, 0); // 获取上月;
    let day = date.getDate(); // 因为Date函数中天设置的0,因此这里是上月最后一天的值
    let days = this.currentFirstWeekDay; // 上月要显示几天
    let weeks: MyDate[] = [];
    while (days > 0) {
      weeks.push(new MyDate(date.getFullYear(), date.getMonth() + 1, day--));
      days--;
    }
    return weeks.sort((a, b) => a.day - b.day); // 因为是从大到小的,排个序
  }

  aboutToAppear() {
    let date = new Date();
    this.currentDay = date.getDate()
    this.currentMonth = date.getMonth() + 1;
    this.currentYear = date.getFullYear();
    this.currentFirstWeekDay = new Date(date.getFullYear(), date.getMonth(), 1).getDay();
    let allDay = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();

    for (let i = 0; i < allDay; i++) {
      this.allDay[i] = i
    }
    this.preMonth = this.getPrevMonthDay()
  }

  refreshDays(month: number, year: number) {
    //上月
    let date = new Date(year, month - 1, 0); // 获取上月;
    let day = date.getDate(); // 因为Date函数中天设置的0,因此这里是上月最后一天的值
    this.currentFirstWeekDay = new Date(year, month - 1, 1).getDay();
    let days = this.currentFirstWeekDay; // 上月要显示几天
    let weeks: MyDate[] = [];
    while (days > 0) {
      weeks.push(new MyDate(date.getFullYear(), date.getMonth() + 1, day--));
      days--;
    }
    weeks.sort((a, b) => a.day - b.day); // 因为是从大到小的,排个序
    this.preMonth = weeks
    //本月
    console.info(`year${year}month${month}`)
    let allDay = new Date(year, month, 0).getDate();
    console.info(`allDay${allDay}`)
    //需要先重置
    this.allDay = []
    for (let i = 0; i < allDay; i++) {
      this.allDay[i] = i
    }
    console.info(`${this.allDay}`)
  }

  refreshDate(month: number) {
    if (month < 1) {
      this.currentMonth = 12
      this.currentYear--
      //重新更新天数
      this.refreshDays(this.currentMonth, this.currentYear)
    }
    else if (month > 12) {
      this.currentMonth = 1
      this.currentYear++
      this.refreshDays(this.currentMonth, this.currentYear)
    }
    else {
      this.currentMonth = month
      this.currentYear = this.currentYear;

      this.refreshDays(this.currentMonth, this.currentYear)
    }
  }

  @Builder
  Header() {
    Row() {
      // Image($rawfile('icon_arrow_l.svg'))
      Image($rawfile('icon_arrow_r.svg'))
        .width(15)
        .height(15)
        .margin({ right: 20 })
        .onClick(() => {
          this.currentMonth--
          this.refreshDate(this.currentMonth)
        })
      Text(`${this.currentYear}年${this.currentMonth}月`)
        .fontSize(20)
      Image($rawfile('icon_arrow_r.svg'))
        .width(15)
        .height(15)
        .margin({ left: 20 })
        .onClick(() => {
          this.currentMonth++

          this.refreshDate(this.currentMonth)
        })
    }
  }

  @Builder
  Week(value: string[]) {
    Column() {
      Grid() {
        ForEach(value, (data: string) => {
          GridItem() {
            Text(data)
              .fontSize(16)
              .fontWeight(FontWeight.Bold)
              .width('100%')
              .textAlign(TextAlign.Center)
          }
        })
      }
      .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
      .columnsGap(10)
      .rowsGap(10)
      .width('90%')
      .height(50)
    }
    .width('100%')
    .margin({ bottom: 10 })
  }

  @Builder
  Day() {
    Grid() {
      ForEach(this.preMonth, (i: MyDate) => {
        GridItem() {
          Text(String(i.day))
            .textAlign(TextAlign.Center)
            .fontSize(16)
            .fontColor(Color.Gray)
        }
        .onClick(() => {
          this.currentMonth--
          console.info(`currentMonth${this.currentMonth}`)
          this.refreshDate(this.currentMonth)
        })
      })
      ForEach(this.allDay, (i: number, index: number) => {
        GridItem() {
          Text(String(i + 1))
            .fontSize(16)
            .fontColor('#ff2e5391')
            .backgroundColor(this.isSelectIndex == index ? '#ff0000' : '')
            .textAlign(TextAlign.Center)
            .onClick(() => {
              console.info('click:', this.currentYear + "-" + this.currentMonth + "-" + (i + 1))
              this.isSelectIndex = index
            })
        }
      })
    }
    .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
    .columnsGap(10)
    .rowsGap(10)
    .width('90%')

  }

  build() {
    Column() {
      this.Header()
      this.Week(this.week)
      this.Day()
    }
  }
}

更多关于HarmonyOS 鸿蒙Next 想实现点击后改变样式的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


可以是可以,但是为什么报错了
04-28 18:28:03.946 11464-19936 E C03900/Ace: [Engine Log]Lifetime: 0.000000s
04-28 18:28:03.946 11464-19936 E C03900/Ace: [Engine Log]Js-Engine: ark
04-28 18:28:03.946 11464-19936 E C03900/Ace: [Engine Log]page: components
04-28 18:28:03.946 11464-19936 E C03900/Ace: [Engine Log]Error message: is not callable
04-28 18:28:03.946 11464-19936 E C03900/Ace: [Engine Log]Cannot get SourceMap info, dump raw stack:
04-28 18:28:03.946 11464-19936 E C03900/Ace: [Engine Log]Stacktrace:
04-28 18:28:03.946 11464-19936 E C03900/Ace: [Engine Log]    at anonymous (entry

is not callable 报这个错,看起来是class用法不对。你可以不用我写的MyDate这个类,还用你原来的逻辑,和isSelectIndex 相关的代码保留就行了。

先理思路,代码是浮云:)

1、抓住重点:这个UI要改变的是单个GridItem中的Text()组件;在确定用数组表示整个月份的数据后,也确定了每个日期有个数组索引 index;控制哪个日期产生变化就可以考虑用一个选中指标变量即可,如:@State selectedIndex = -1,然后在组件属性调用时用此变量进行选中判断进而决定属性的相应赋值,具体改变哪个属性自己可选择。

2、以变换背景色举例:Text().backgroundColor(index == this.selectedIndex ? Color.A : Color.B) 即达成所愿。至于选中指标变量的更新就在其 .onClick() 中实现 this.selectedIndex = index; 即可,直接简单,不要想复杂了。

另,代码完全可以大大简化:有关 preMonth 的数据结构使用不合理,其中的年、月数据完全是重复的;只需保留一个日期值就够了,当年、当月已经有变量进行保存了,前月,下月只需 +1,-1 即可,没必要整那么多变量,一个简单的事给整复杂了:)有些中间计算变量也都整成 @State,过度使用状态装饰器了哟。。。

不知哪些不需要State呀感觉都挺需要的,求指点,

一个简单的筛选方法:

  1. 收拢所有组件中的方法;

  2. 在IDE中选中声明的属性变量名,按 Ctrl + F 进入搜索;

  3. build() {}, @Builder {} 的花括号中有无颜色提示存在;如果所有UI相关方法中都没有存在,则可去除状态装饰器。

试一下list容器组件 + checkBox/checkBoxGroup基础组件?

官方文档:

list:

https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V2/ts-container-list-0000001477981213-V2

checkBox/checkBoxGroup:

https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V2/ts-basic-components-checkbox-0000001427744808-V2

如果是个人开发,建议使用已经有的组件,后期有精力了在自己开发原生组件。

🤣你这代码太长了​,对于更新ui的方法

可以尝试在refresh里 使用 this.dArray.splice(index, 1, this.dArray[index]); ​

参考:https://developer.huawei.com/consumer/cn/forum/topic/0202149168419486295?fid=0109140870620153026

实在不行的话,回复我,我再抽时间把你的demo完整改一下。

refresh不是下拉刷新吗,还是有点不理解 麻烦啦,

我想要的是那种选中之后改变样子,选择其他的继续更换选中对象,

类似上面图片这样的

在HarmonyOS中,可以通过ArkUI框架实现点击后改变样式的功能。使用@State装饰器来管理组件的状态,并在点击事件中更新状态,从而触发UI的重新渲染。以下是一个简单的示例:

@Entry
@Component
struct MyComponent {
  @State isClicked: boolean = false;

  build() {
    Column() {
      Button(this.isClicked ? 'Clicked' : 'Click Me')
        .onClick(() => {
          this.isClicked = !this.isClicked;
        })
        .backgroundColor(this.isClicked ? '#FF0000' : '#00FF00')
        .padding(10)
        .margin(10)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

在这个示例中,@State装饰器用于管理isClicked状态。当按钮被点击时,onClick事件会切换isClicked的值,从而改变按钮的文本和背景颜色。

在HarmonyOS鸿蒙Next中实现点击后改变样式,可以使用@State装饰器来管理组件的状态变化。首先,定义一个@State变量来存储样式状态,然后在点击事件中更新该变量。例如,使用Button组件时,可以在onClick事件中改变@State变量的值,从而触发UI更新,实现样式的动态变化。例如:

@Entry
@Component
struct MyComponent {
  @State isClicked: boolean = false;

  build() {
    Column() {
      Button(this.isClicked ? 'Clicked' : 'Click Me')
        .backgroundColor(this.isClicked ? '#FF0000' : '#00FF00')
        .onClick(() => {
          this.isClicked = !this.isClicked;
        })
    }
  }
}

点击按钮后,背景颜色和文本内容会根据isClicked状态变化。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!