HarmonyOS期末项目——作业清单(四)通用工具类

系列文章目录

HarmonyOS期末项目——作业清单(一)项目介绍和应用主页面设计

HarmonyOS期末项目——作业清单(二)任务创建与编辑

HarmonyOS期末项目——作业清单(三)搭建关系型数据库

HarmonyOS期末项目——作业清单(完结篇)组件与视图


目录

系列文章目录

前言

一、关键技术

1.1 日志类

1.2 时间工具

1.3 媒体查询

二、示意图

三、日志类

3.1 功能简介

3.2 代码文件

四、时间工具

4.1 功能简介

4.2 代码文件

五、媒体查询工具类

5.1 功能简介

5.2 代码文件

六、遇到的问题及解决方案

6.1 任务列表 UI 不更新

6.2 搜索功能不工作

6.3 日志信息不完整

总结


前言

作业清单在日常生活和工作中非常重要,一个高效的作业清单工具能帮助更好地管理任务,提高效率。在前几篇文章中,介绍了作业清单应用的概述、主页面设计、任务创建和编辑,以及关系型数据库的搭建。

本篇文章重点介绍作业清单的通用工具类,包括日志类、时间工具和媒体查询。

  • 日志类:记录应用运行时的信息,如错误日志和调试信息,帮助定位和修复问题,并分析运行情况以优化性能。
  • 时间工具:处理时间相关的功能,如获取当前时间、比较时间和格式化时间,提升应用的灵活性和可用性。
  • 媒体查询:适应不同屏幕尺寸的设备,确保网页在各种设备上都有最佳用户体验。


一、关键技术

1.1 日志类

  • 日志模块:使用日志库(如 `hilog`)来记录应用运行时的信息,包括错误日志、调试信息等。
  • 日志级别:定义不同的日志级别(如 debug、info、warn、error),并实现相应的方法来记录不同级别的日志信息。
  • 日志前缀和服务域:允许在日志记录时添加前缀和服务域,以便在日志中标识日志的来源。
  • 模块化设计:将日志记录功能封装在独立的类中,便于日后维护和扩展。
  • 日志输出配置:配置日志输出的格式和目标,如控制台输出、文件输出等。

1.2 时间工具

  • 时间获取:提供获取当前时间的功能,支持多种时间格式。
  • 时间比较:实现时间比较功能,便于任务的截止日期和当前时间进行比较。
  • 时间格式化:提供将时间对象格式化为字符串的功能,支持多种格式(如 YYYY-MM-DD、HH:mm:ss 等)。
  • 时间计算:实现时间的加减计算功能,如计算任务的剩余时间。
  • 时区处理:处理不同地区的时区差异,确保时间的准确性和一致性。

1.3 媒体查询

  • 媒体查询API:使用媒体查询 API(如 `mediaquery` 模块)监听媒体查询的变化,响应不同的屏幕尺寸和设备特性。
  • 响应式设计:根据不同的媒体查询结果,调整页面布局和样式,适应小屏幕(sm)、中等屏幕(md)和大屏幕(lg)。
  • 事件监听:实现媒体查询变化时的事件监听,调用相应的回调函数处理逻辑。
  • 暗黑模式支持:通过媒体查询检测系统的暗黑模式设置,并相应调整应用的主题和样式。
  • 自适应布局:利用 CSS 和 JavaScript 配合,实现页面在不同设备上的自适应布局。

二、示意图

三、日志类

Logger.ets

封装日志记录功能,支持不同级别的日志输出。


3.1 功能简介

  • 提供了 debug、info、warn 和 error 四个方法,用于输出不同级别的日志信息。
  • 可以指定日志的前缀和服务域,以便在日志中标识日志来源。
  • 使用 hilog 模块实现日志输出,通过调用相应的方法将日志信息发送到系统日志记录器。
  • 特点:
  • 构造函数可以接受两个参数:prefix 用于标识日志的前缀,domain 表示服务域,其取值范围为 0x0 到 0xFFFFF。
  • 提供了四个方法,分别对应不同的日志级别,使得可以根据需要输出不同级别的日志信息。
  • 采用了模块化设计,将日志输出功能封装在独立的类中,便于日后维护和扩展。

3.2 代码文件

import hilog from '@ohos.hilog';
class Logger {
  private domain: number;
  private prefix: string;
  private format: string = '%{public}s, %{public}s';

 
  constructor(prefix: string = 'MyApp', domain: number = 0xFF00) {
    this.prefix = prefix;
    this.domain = domain;
  }

  debug(...args: string[]): void {
    hilog.debug(this.domain, this.prefix, this.format, args);
  }

  info(...args: string[]): void {
    hilog.info(this.domain, this.prefix, this.format, args);
  }

  warn(...args: string[]): void {
    hilog.warn(this.domain, this.prefix, this.format, args);
  }

  error(...args: string[]): void {
    hilog.error(this.domain, this.prefix, this.format, args);
  }
}

export default new Logger('Rdb', 0xFF00)

四、时间工具


提供时间格式化、时间计算等功能。


DDLState.ets

DDL状态组件,显示DDL状态信息。

4.1 功能简介

  • 实现了对待办事项进行按照紧急程度分类显示的功能,分为非常紧急、紧急、还有时间和该开始了四个分类。
  • 提供了搜索功能,可以根据任务名称进行搜索并显示结果。
  • 支持对任务进行编辑,包括勾选完成、修改截止日期等操作。
  • 实现了点击待办事项后显示任务详情的功能,包括任务名称、截止日期等信息。
  • 使用了 TaskTable 类来处理与任务数据相关的数据库操作,实现了对任务数据的增删改查功能。
  • 通过 TaskListItemData 类来定义待办事项的数据结构,包括任务名称、截止日期等信息。
  • 利用 Logger 类来记录日志信息,方便调试和错误排查。
  • 使用了 CustomDialogController 和 TaskItemDialog_ViewOnly 来实现任务详情的弹窗显示功能。
  • 采用 OhOS 提供的 UI 组件和布局方式,实现了待办事项的分类显示和搜索功能。

4.2 代码文件


@Component

export default struct DDLState {
  @Link tasks: Array<TaskListItemData>
  @Link categoryList: TaskCategoryData[]
  @State isEditing: boolean = false
  @State dialogIsAddNew: boolean = true
  @State taskItem: TaskListItemData = new TaskListItemData()
  private taskTable: TaskTable = new TaskTable(() => {});
  private dialogSelectedIndex: number = -1

  dialogController_view: CustomDialogController = new CustomDialogController({
    builder: TaskItemDialog_ViewOnly({
      taskItem: $taskItem,
      categoryList: $categoryList
    }),
    alignment: DialogAlignment.Bottom,
    customStyle: true
  })

  @Builder TaskList_ListItem(item: TaskListItemData) {
    Column() {
      Row() {
        Row() {
          if (!this.isEditing) {
            Checkbox()
              .select(item.is_completed)
              .onChange((value: boolean) => {
                animateTo({duration: 300, curve: Curve.EaseInOut}, () => {
                  item.is_completed = value
                  this.updateExistingTask(item)
                })
              })
              .margin({ right: 10 })
          }
          Text(item.task_name)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
            .maxLines(1)
            .width('60%')
        }
        Row() {
          Column() {
            Text(getDateString(item.due_date_stamp))
              .fontSize(16)
            Text(getTimeString(item.due_date_stamp))
              .fontSize(13)
          }.alignItems(HorizontalAlign.End)
          .margin({ right: 10 })

          if (!item.is_completed) Button({ type: ButtonType.Circle, }) {
            Text(' ')
          }
          .backgroundColor(CommonConstants.DDL_COLOR[item.getDDLState()])
          .height(12)
          .width(12)
        }

      }.justifyContent(FlexAlign.SpaceBetween)
      .height(56)
      .width('100%')
      .padding({ left: 12, right: 12 })

      Progress({value: 100 - item.getDDLPer()})
        .margin({bottom: 10})
        .color(CommonConstants.DDL_COLOR[item.getDDLState()])
    }
  }

  @Builder TaskList_DDLState(text: string, state: string) {
    Text(text)
      .fontSize(20)
      .width('100%')
      .margin({ bottom: 10, top: 20})
      .textAlign(TextAlign.Start)
      .padding({ left: 12, right: 12 })

    List() {
     
      ForEach(this.tasks, (item: TaskListItemData) => {
        if (!item.is_completed && item.getDDLState() == state) ListItem() {
          this.TaskList_ListItem(item)
        }.width('100%')
        .backgroundColor(0xffffff)
        .onClick(() => {
          this.taskItem = item
          this.dialogController_view.open()
        })
      })
    }
    .width('100%')
    .borderRadius(20)
    .divider({ strokeWidth: 1 })
    .margin({ bottom: 20 })
  }

  updateExistingTask(taskData: TaskListItemData) {
    this.taskTable.updateData(taskData, () => {})
    let new_task = this.tasks
    this.tasks = []
    new_task[this.dialogSelectedIndex] = taskData
  
    this.tasks = new_task // 触发 UI 刷新
    this.dialogSelectedIndex = -1
  }
  querySearchTask(searchVal: string, callback?: Function) {
    
    this.taskTable.queryTaskName(`%${searchVal}%`, (searchRes) => {
      this.tasks = []
      searchRes.forEach(item => {this.tasks.push(item)})
      for (let i = 0; i < this.tasks.length; ++i) {
        this.tasks[i].setAll(this.categoryList)
      }
      if(callback !== undefined) callback()
    }, (searchVal == ''))
  }
  


  build() {
    Column() {
      Stack({alignContent: Alignment.Bottom}) {
        Navigation() { // UI 标题栏
          // UI 搜索

          if (!this.isEditing) Search()
            // .onClick(() => { this.isOnSearch = true})
            .onSubmit((value: string) => {
              this.querySearchTask(value)
            })
              // .padding({ left: 12, right: 12 })
            .width('90%')

          Column() {
            // UI 待办事项界面
            Scroll() {
              Column() {
                // UI 待办事项列表
                this.TaskList_DDLState('非常紧急', 'critical')
                this.TaskList_DDLState('紧急', 'hard')
                this.TaskList_DDLState('还有时间', 'medium')
                this.TaskList_DDLState('该开始了', 'easy')
              }
              .padding({ left: 12, right: 12, bottom: 10, top: 10 })
              .margin({bottom: 40})
              // .height('70%')
              .justifyContent(FlexAlign.Start)
            }.edgeEffect(EdgeEffect.Spring)
            .scrollBar(BarState.Off)
          }
          .justifyContent(FlexAlign.SpaceBetween)
        }
        .height('100%')
        .width('100%')
        .titleMode(NavigationTitleMode.Mini)
        .hideBackButton(true)
        .mode(NavigationMode.Stack)
        .title('截止时间')
      }.height('100%')
    }.width('100%')
    .height('100%')
  }
}

function getDateString(date_stamp: number): string {
  let date: Date = new Date()
  date.setTime(date_stamp)
  Logger.debug(`TaskList: datestamp = ${date_stamp}, date = ${date.toLocaleDateString()}`)
  let ds: string[] = date.toLocaleDateString().split('/')
  let res: string = `${ds[2]}/${ds[0]}/${ds[1]}`
  return res
}

function getTimeString(date_stamp: number): string {
  let date: Date = new Date()
  date.setTime(date_stamp)
  Logger.debug(`TaskList: datestamp = ${date_stamp}, date = ${date.toLocaleTimeString()}`)
  return date.toLocaleTimeString()
}

五、媒体查询工具类

MediaQuery.ets 

媒体查询工具类,提供媒体查询功能,用于检测不同设备尺寸和暗模式的变化。

5.1 功能简介

  • 通过 mediaquery 模块监听媒体查询的变化,包括屏幕宽度和暗黑模式等。
  • 根据不同的媒体查询结果,确定当前屏幕的类型,包括小屏幕(sm)、中等屏幕(md)和大屏幕(lg)。
  • 提供了对应于不同屏幕类型的回调函数,用于处理屏幕类型变化时的逻辑。
  • 使用了 mediaquery 模块提供的 matchMediaSync 方法来进行媒体查询的同步匹配。
  • 使用了 on 方法来监听媒体查询结果的变化,并在变化时调用相应的回调函数处理。
  • 通过 console.info 方法打印出当前屏幕类型,方便调试和查看。
  • 通过 screenType 属性记录当前屏幕类型,方便其他模块或组件根据屏幕类型进行适配。

5.2 代码文件

import mediaquery from '@ohos.mediaquery';
import deviceInfo from '@ohos.deviceInfo';

class MediaQuery {
  smListener = mediaquery.matchMediaSync('(width < ' + 520 + 'vp)');
  mdListener = mediaquery.matchMediaSync('(width >= ' + 520 + 'vp) and (width <= ' + 840 + 'vp)');
  lgListener = mediaquery.matchMediaSync('(width > ' + 840 + 'vp)');
  darkmodeListener = mediaquery.matchMediaSync('screen and (dark-mode: true)');
  portraitFuncSm = null;
  portraitFuncMd = null;
  portraitFuncLg = null;
  portraitFuncDarkmode = null;
  screenType: string = ''

  constructor() {
    var that = this;
    this.smListener = mediaquery.matchMediaSync('(width <= ' + 672 + ')');
    this.mdListener = mediaquery.matchMediaSync('(width > ' + 672 + ') and (width <= ' + 1250 + ')');
    this.lgListener = mediaquery.matchMediaSync('(width > ' + 1250 + ')');
    this.darkmodeListener = mediaquery.matchMediaSync('screen and (dark-mode: true)');
    this.portraitFuncSm = this.onPortraitSm.bind(this)
    this.smListener.on('change', this.portraitFuncSm)
    this.portraitFuncMd = this.onPortraitMd.bind(this)
    this.mdListener.on('change', this.portraitFuncMd)
    this.portraitFuncLg = this.onPortraitLg.bind(this)
    this.lgListener.on('change', this.portraitFuncLg)
  }
  public onPortraitSm(mediaQueryResult) {
    if (mediaQueryResult.matches) {
      this.screenType = 'sm'
      console.info('sm')
    }
  }

  public onPortraitMd(mediaQueryResult) {
    if (mediaQueryResult.matches) {
      this.screenType = 'md'
      console.info('md')
    }
  }

  public onPortraitLg(mediaQueryResult) {
    if (mediaQueryResult.matches) {
      this.screenType = 'lg'
      console.info('lg')
    }
  }
}

export default new MediaQuery()

六、遇到的问题及解决方案

6.1 任务列表 UI 不更新


问题描述: 在更新任务状态(如完成任务)后,任务列表的 UI 有时不会自动刷新,导致用户看不到最新的任务状态。

解决方案:
通过重新分配 `tasks` 数组来触发 UI 刷新。在更新任务数据后,将 `tasks` 数组置为空,再将更新后的任务数组重新赋值给 `tasks`。

 

  updateExistingTask(taskData: TaskListItemData) {
    this.taskTable.updateData(taskData, () => {})
    let new_task = this.tasks
    this.tasks = []
    new_task[this.dialogSelectedIndex] = taskData
    this.tasks = new_task // 触发 UI 刷新
    this.dialogSelectedIndex = -1
  }


 

6.2 搜索功能不工作


问题描述: 在使用搜索功能时,无法正确过滤和显示符合条件的任务。

解决方案:
确保在查询任务名称时,使用了正确的 SQL 通配符,并将搜索结果正确地赋值给 `tasks` 数组。
 

  querySearchTask(searchVal: string, callback?: Function) {
    this.taskTable.queryTaskName(`%${searchVal}%`, (searchRes) => {
      this.tasks = []
      searchRes.forEach(item => { this.tasks.push(item) })
      for (let i = 0; i < this.tasks.length; ++i) {
        this.tasks[i].setAll(this.categoryList)
      }
      if (callback !== undefined) callback()
    }, (searchVal == ''))
  }


 

6.3 日志信息不完整


问题描述: 日志记录的信息不够详细,无法提供足够的调试和错误排查信息。

解决方案:
增强日志记录的详细程度,特别是在关键操作和方法调用时添加日志。
使用 `Logger` 类在关键步骤中记录详细的调试信息。
 

  function getDateString(date_stamp: number): string {
    let date: Date = new Date()
    date.setTime(date_stamp)
    Logger.debug(`TaskList: datestamp = ${date_stamp}, date = ${date.toLocaleDateString()}`)
    let ds: string[] = date.toLocaleDateString().split('/')
    let res: string = `${ds[2]}/${ds[0]}/${ds[1]}`
    return res
  }
  
  function getTimeString(date_stamp: number): string {
    let date: Date = new Date()
    date.setTime(date_stamp)
    Logger.debug(`TaskList: datestamp = ${date_stamp}, date = ${date.toLocaleTimeString()}`)
    return date.toLocaleTimeString()
  }
  


总结

通过合理使用日志类、时间工具和媒体查询这些关键技术,可以极大地提升任务管理应用的性能和用户体验。日志类为我们提供了详细的运行信息和调试支持,时间工具让我们可以灵活处理各种时间相关操作,而媒体查询确保了应用的响应性和自适应布局。这些技术的结合,使得我们的任务管理应用不仅功能强大,而且易于维护和扩展。

  • 26
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个关于电影主题的HTML网页设计作业的示例,以千与千寻为例: ```html <!DOCTYPE html> <html> <head> <title>千与千寻</title> <style> /* CSS样式 */ body { font-family: Arial, sans-serif; background-color: #f2f2f2; } h1 { color: #333333; text-align: center; } .container { max-width: 800px; margin: 0 auto; padding: 20px; background-color: #ffffff; border-radius: 5px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); } .movie-info { display: flex; align-items: center; margin-bottom: 20px; } .movie-info img { width: 150px; height: auto; margin-right: 20px; } .movie-info h2 { margin: 0; } .movie-info p { margin: 0; } </style> </head> <body> <div class="container"> <h1>千与千寻</h1> <div class="movie-info"> <img src="千与千寻海报.jpg" alt="千与千寻海报"> <div> <h2>电影信息</h2> <p>导演:宫崎骏</p> <p>主演:柊瑠美、入野自由</p> <p>上映日期:2001年7月20日</p> <p>片长:125分钟</p> </div> </div> <h2>剧情简介</h2> <p>《千与千寻》是宫崎骏执导的一部动画电影,讲述了一个小女孩千寻在神秘的世界中寻找父母的故事。影片以细腻的画面和深刻的寓意赢得了广大观众的喜爱。</p> <h2>影评</h2> <p>这是一部非常有意义的电影,它通过一个小女孩的冒险故事,探讨了成长、勇气和爱的主题。宫崎骏的动画技巧和故事情节都非常出色,让人流连忘返。</p> </div> </body> </html> ``` 这个示例包含了一个简单的电影主题网页,其中包括电影的基本信息、剧情简介和影评。你可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值