跳到主要内容
版本:Next 🚧

制定方案

在开始开发之前制定技术方案可以帮助我们更好地理解需求,明确开发内容,减少开发过程中因方案变动而产生的额外成本。

目录结构

todolist/               项目根目录
app/ 工作目录
src/ 源码目录
tasklist.c 任务列表数据管理
tasklist.h 任务列表数据管理
ui_tasklist.c 界面上的任务列表
ui_tasklist.h 界面上的任务列表
main.c 程序主入口

程序的界面依赖一些外部资源文件(xml、css),出于打包和发布便利性上的考虑,需要有个工作目录来存放程序的可执行文件和资源文件,该目录命名为 app

源文件划分方面,任务列表的数据管理代码较为独立,而任务列表部件的交互实现较为复杂,因此将它们划分到独立的文件中,其余的交互代码较为简单,都写到 main.c 中。

界面描述方式

除去任务列表需要在运行时动态更新外,其它元素都是静态的,因此,使用 xml 描述界面结构,而任务列表则使用 C 代码创建和更新。

布局方式

主界面需要在窗口内垂直水平居中,可将根布局设置为 flex 容器,然后用 justify-content 和 align-items 属性控制主界面水平和垂直对齐方式。

任务数量和筛选按钮的左右对齐方式也可以用 flex 布局实现。先将它们的父部件设为 flex 容器,然后将任务数量的 margin-right 设为 auto 以占满剩余空间,从而将筛选按钮挤到最右端。

任务列表中,状态图标和删除图标尺寸固定,用 flex: none 禁止拉伸和收缩。中间文本自由伸缩占满剩余空间,用 flex: auto 即可。

数据管理

任务列表数据包含每个任务的状态和名称,状态有完成和未完成,为方便增删改操作,数据还应该包含 id,类型为 int,生成方式是从 1 开始递增。

任务列表是动态增删的,为方便操作任务数据,应使用 <yutil.h> 中提供的数据结构 list_t 来存储,并提供任务列表的初始化、追加、删除、更新、筛选函数。

界面交互

标题:

当前时间可以用标准库的 time() 函数获取,调用 localtime() 转换成 struct tm 类型, 然后用 strftime() 函数格式化成字符串。

任务数量:

任务数量随任务列表更新,可在追加和删除任务时调用相关函数来更新任务数量。

筛选按钮:

筛选按钮有三个,为便于区分它们所携带的筛选参数,可给它们设置 data-value 属性。

给按钮的父部件添加 click 事件处理器,先通过事件目标找到筛选按钮部件,然后获取 data-value 属性,将其转换为参数传递给筛选函数以获取符合条件的任务列表数据,之后使用该数据重新创建任务列表。

输入框:

添加 keydown 事件处理器,当事件中的按键码为 KEY_ENTER 时往任务列表追加任务并清空输入框内容。

任务列表:

添加任务列表创建函数,参数是任务列表数据,方法先清空任务列表部件,然后是遍历任务列表数据,为每一项数据创建任务部件。为了方便后续的更新和删除操作,需要将任务的 id 保存为任务部件的属性,属性名为 data-id

给任务列表部件添加 click 事件处理器,在里面实现对状态图标和删除图标的 click 事件处理,事件目标的区分方法是判断它及其父部件是否有包含状态图标或删除图标的类名。

任务状态切换涉及部件和数据的操作。对于部件操作,状态的改变只是影响部件的样式,因此只需要根据状态来更改类名。而对于数据操作,调用数据管理模块提供的更新函数即可。

任务的删除功能需要将数据和部件一同删除,这两个操作只需要调用现有的函数即可。