HarmonyOS7 ArkUI 任务看板 - Kanban 分组、状态切换实战 文章目录前言这个案例练的是什么数据流别写散单独看这几段片段 1getPriorityColor(priority: string): ResourceColor {片段 2getTagColor(tag: string): ResourceColor {使用方式完整实现写到项目里要注意前言我看这份代码时最先关注的不是配色而是状态怎么推动页面变化。只要这条线顺了后面的 UI 调整都不难。它的主线是任务看板细节落在Kanban 分组、状态切换。这些细节刚好能把页面状态、用户操作和组件刷新串起来。这个案例练的是什么TaskKanbanBoard不是一个只展示静态内容的页面。它会根据用户点击、输入、切换或计时来改变界面所以阅读代码时可以先抓三条线观察点在这个案例里的表现页面主题任务看板主要文案用户登录界面设计,完成登录/注册页的 UI 设计,数据库表结构设计,设计用户和订单相关的数据表,接口文档编写,整理 REST API 文档| 常用组件 |Column,ForEach,Row,Scroll,Text|| 适合练习 | 状态驱动 UI、条件样式、列表渲染、事件回调 |数据流别写散ArkUI 的页面刷新依赖状态变化。下面这些State字段就是页面的“开关”和“数据源”不用手动找 DOM也不用自己通知某个控件刷新。状态字段类型我会怎么理解它tasksKanbanTask_rl2i[]列表数据源通常会被ForEach消费selectedTaskKanbanTask_rl2inullfilterPrioritystring记录页面当前选择、输入或展示状态一个经验先把State看完再看build()页面逻辑会清楚很多。否则很容易被一长串布局代码带偏。单独看这几段片段 1getPriorityColor(priority: string): ResourceColor {这段代码承担的是页面里的“判断”或“动作”把它从布局里抽出来后build()会清爽很多。后面要加新条件也不会到处翻 UI 代码。getPriorityColor(priority:string):ResourceColor{switch(priority){case高:return#EF4444case中:return#F59E0Bdefault:return#6B7280}}片段 2getTagColor(tag: string): ResourceColor {这段代码承担的是页面里的“判断”或“动作”把它从布局里抽出来后build()会清爽很多。后面要加新条件也不会到处翻 UI 代码。getTagColor(tag:string):ResourceColor{constmap:Recordstring,string{设计:#8B5CF6,前端:#3B82F6,后端:#10B981,测试:#F59E0B,产品:#EC4899,文档:#6366F1,运维:#14B8A6}returnmap[tag]??#6B7280}使用方式把下面代码放进 ArkTS 页面文件中即可运行。用于正式项目时我会继续把数据模型、卡片 Builder 和页面事件拆出去页面文件只负责组合。建议练习顺序先改状态字段 - 再改交互事件 - 最后调整 UI 样式 检查重点点击是否刷新、列表 key 是否稳定、条件样式是否集中管理这份代码可以继续扩展的方向把模拟数据替换成接口数据抽出复用卡片组件增加空状态和异常状态补充深色模式或主题色适配对输入类场景增加校验提示完整实现// TaskKanbanBoard - 任务看板Kanban 分组、状态切换interfaceKanbanTask_rl2i{id:numbertitle:stringdesc:stringpriority:stringtag:stringassignee:stringdueDate:stringstatus:string}interfaceKanbanColumn_lphl{key:stringlabel:stringcolor:ResourceColor bgColor:ResourceColor count:number}EntryComponentstruct TaskKanbanBoard{Statetasks:KanbanTask_rl2i[][{id:1,title:用户登录界面设计,desc:完成登录/注册页的 UI 设计,priority:高,tag:设计,assignee:张三,dueDate:6/8,status:todo},{id:2,title:数据库表结构设计,desc:设计用户和订单相关的数据表,priority:高,tag:后端,assignee:李四,dueDate:6/7,status:todo},{id:3,title:接口文档编写,desc:整理 REST API 文档,priority:中,tag:文档,assignee:王五,dueDate:6/10,status:todo},{id:4,title:首页轮播组件,desc:开发可配置的 Swiper 轮播图,priority:中,tag:前端,assignee:张三,dueDate:6/9,status:inprogress},{id:5,title:支付模块集成,desc:集成微信/支付宝支付 SDK,priority:高,tag:后端,assignee:李四,dueDate:6/12,status:inprogress},{id:6,title:单元测试编写,desc:核心业务逻辑单测覆盖 80%,priority:低,tag:测试,assignee:王五,dueDate:6/15,status:inprogress},{id:7,title:需求文档确认,desc:与产品经理确认功能需求,priority:高,tag:产品,assignee:赵六,dueDate:6/5,status:done},{id:8,title:开发环境搭建,desc:配置本地开发和测试环境,priority:中,tag:运维,assignee:张三,dueDate:6/4,status:done},{id:9,title:原型图评审,desc:组织团队进行原型图走查,priority:中,tag:设计,assignee:赵六,dueDate:6/6,status:done}]StateselectedTask:KanbanTask_rl2i|nullnullStatefilterPriority:string全部privatecolumns:KanbanColumn_lphl[][{key:todo,label:待办,color:#64748B,bgColor:#F1F5F9,count:0},{key:inprogress,label:进行中,color:#3B82F6,bgColor:#EFF6FF,count:0},{key:done,label:已完成,color:#22C55E,bgColor:#F0FFF4,count:0}]privatepriorities:string[][全部,高,中,低]getPriorityColor(priority:string):ResourceColor{switch(priority){case高:return#EF4444case中:return#F59E0Bdefault:return#6B7280}}getTagColor(tag:string):ResourceColor{constmap:Recordstring,string{设计:#8B5CF6,前端:#3B82F6,后端:#10B981,测试:#F59E0B,产品:#EC4899,文档:#6366F1,运维:#14B8A6}returnmap[tag]??#6B7280}moveTask(taskId:number,direction:string){constorder[todo,inprogress,done]this.tasksthis.tasks.map(t{if(t.idtaskId){constidxorder.indexOf(t.status)constnewIdxdirectionnext?Math.min(idx1,2):Math.max(idx-1,0)t.statusorder[newIdx]returnt}returnt})}filteredTasks(status:string):KanbanTask_rl2i[]{returnthis.tasks.filter(tt.statusstatus(this.filterPriority全部||t.prioritythis.filterPriority))}BuildertaskCard(task:KanbanTask_rl2i,colKey:string){Column({space:8}){// 优先级 标签Row({space:8}){Row({space:4}){Circle({width:8,height:8}).fill(this.getPriorityColor(task.priority))Text(task.priority优先).fontSize(11).fontColor(this.getPriorityColor(task.priority))}Blank()Text(task.tag).fontSize(11).fontColor(this.getTagColor(task.tag)).padding({left:6,right:6,top:2,bottom:2}).backgroundColor(this.getTagColor(task.tag)20).borderRadius(4)}.width(100%)Text(task.title).fontSize(14).fontWeight(FontWeight.Medium).fontColor(#1A1A1A).maxLines(2).textOverflow({overflow:TextOverflow.Ellipsis})Text(task.desc).fontSize(12).fontColor(#6B7280).maxLines(1).textOverflow({overflow:TextOverflow.Ellipsis})Row(){Text( task.assignee).fontSize(11).fontColor(#9CA3AF)Blank()Text( task.dueDate).fontSize(11).fontColor(#9CA3AF)// 移动按钮if(colKey!todo){Text(◀).fontSize(14).fontColor(#3B82F6).margin({left:8}).onClick(()this.moveTask(task.id,prev))}if(colKey!done){Text(▶).fontSize(14).fontColor(#22C55E).margin({left:4}).onClick(()this.moveTask(task.id,next))}}.width(100%)}.width(100%).padding(12).backgroundColor(#FFFFFF).borderRadius(10).shadow({radius:4,color:#00000010,offsetX:0,offsetY:2}).margin({bottom:10})}build(){Column(){// 顶部标题Column({space:12}){Row(){Column({space:2}){Text(任务看板).fontSize(22).fontWeight(FontWeight.Bold).fontColor(#1A1A1A)Text(共 this.tasks.length 个任务).fontSize(13).fontColor(#9CA3AF)}.alignItems(HorizontalAlign.Start)Blank()Text( 新任务).fontSize(14).fontColor(#FFFFFF).padding({left:14,right:14,top:8,bottom:8}).backgroundColor(#3B82F6).borderRadius(20)}.width(100%)// 优先级筛选Row({space:8}){ForEach(this.priorities,(p:string){Text(p).fontSize(13).fontColor(this.filterPriorityp?#FFFFFF:#6B7280).padding({left:14,right:14,top:6,bottom:6}).backgroundColor(this.filterPriorityp?#3B82F6:#F3F4F6).borderRadius(16).onClick((){this.filterPriorityp})})}}.width(100%).padding({left:16,right:16,top:50,bottom:12}).backgroundColor(#FAFAFA)// 看板列横向滚动Scroll(){Row({space:12}){ForEach(this.columns,(col:KanbanColumn_lphl){Column({space:10}){// 列标题Row({space:8}){Row({space:6}){Circle({width:10,height:10}).fill(col.color)Text(col.label).fontSize(14).fontWeight(FontWeight.Bold).fontColor(col.color)}Blank()Text(this.filteredTasks(col.key).length).fontSize(13).fontColor(#FFFFFF).width(22).height(22).textAlign(TextAlign.Center).backgroundColor(col.color).borderRadius(11)}.width(100%).padding({bottom:8}).border({width:{bottom:0.5},color:#E5E7EB})// 任务卡片if(this.filteredTasks(col.key).length0){Column(){Text(暂无任务).fontSize(13).fontColor(#D1D5DB)}.width(100%).height(80).justifyContent(FlexAlign.Center)}else{ForEach(this.filteredTasks(col.key),(task:KanbanTask_rl2i){this.taskCard(task,col.key)})}}.width(220).padding(14).backgroundColor(col.bgColor).borderRadius(16)})}.padding({left:16,right:16,top:8,bottom:30})}.scrollable(ScrollDirection.Horizontal).layoutWeight(1).backgroundColor(#F9FAFB)}.width(100%).height(100%).backgroundColor(#F9FAFB)}}写到项目里要注意这个案例可以当成一个小模板先把页面会变的东西放进状态再用函数或 Builder 处理重复逻辑最后让布局只关心展示。写 HarmonyOS7 页面时这个顺序通常比一上来堆 UI 更稳。