RN for OpenHarmony 实战 TodoList 项目:按优先级筛选
#不是所有任务都一样重要。有些任务今天必须完成,有些任务下周再做也行。优先级就是用来区分这种重要程度的。在我们的 TodoList 应用中,任务有三个优先级:高、中、低。当任务列表变长时,用户可能想"先看看有哪些高优先级的任务要处理"。优先级筛选就是为这个需求服务的。和状态筛选不同的是,优先级筛选有颜色的概念。高优先级是红色,中优先级是黄色,低优先级是绿色。这种颜色编码让筛选按钮本身就传达了信息。
#
案例开源地址:https://atomgit.com/lqjmac/rn_openharmony_todolist
优先级的意义
不是所有任务都一样重要。有些任务今天必须完成,有些任务下周再做也行。优先级就是用来区分这种重要程度的。
在我们的 TodoList 应用中,任务有三个优先级:高、中、低。当任务列表变长时,用户可能想"先看看有哪些高优先级的任务要处理"。优先级筛选就是为这个需求服务的。
和状态筛选不同的是,优先级筛选有颜色的概念。高优先级是红色,中优先级是黄色,低优先级是绿色。这种颜色编码让筛选按钮本身就传达了信息。
优先级筛选类型的定义
首先定义筛选的类型:
type PriorityFilter = 'all' | 'high' | 'medium' | 'low';
四个选项
比状态筛选多了一个维度。除了三个优先级值,还有一个 'all' 表示不筛选,显示所有任务。
与任务优先级的关系
任务的优先级类型是 'high' | 'medium' | 'low',筛选类型多了一个 'all'。这是因为筛选需要一个"不筛选"的选项,而任务本身必须有一个确定的优先级。
优先级颜色的定义
优先级有对应的颜色:
const priorityColors = {
high: '#ff6b6b',
medium: '#ffd93d',
low: '#6bcb77',
};
颜色的语义
这是交通灯的颜色系统:
- 红色
#ff6b6b表示高优先级,像红灯一样警示"停下来处理这个" - 黄色
#ffd93d表示中优先级,像黄灯一样提醒"注意一下" - 绿色
#6bcb77表示低优先级,像绿灯一样表示"可以慢慢来"
为什么用这套颜色
这套颜色是全球通用的,用户不需要学习就能理解。看到红色就知道重要,看到绿色就知道不急。这种直觉性的设计能降低用户的认知负担。
筛选状态的管理
const [priorityFilter, setPriorityFilter] = useState<PriorityFilter>('all');
默认值
默认是 'all',显示所有优先级的任务。用户打开应用时应该能看到全貌,而不是被筛选后的部分视图。
状态命名
变量名是 priorityFilter 而不是 priority,因为这是筛选条件,不是任务的优先级。清晰的命名能避免混淆。
筛选按钮组的实现
看看优先级筛选按钮是怎么实现的:
<View style={styles.filterContainer}>
<View style={styles.filterGroup}>
{(['all', 'high', 'medium', 'low'] as PriorityFilter[]).map(p => (
<TouchableOpacity
key={p}
style={[styles.filterBtn, priorityFilter === p && {backgroundColor: p === 'all' ? theme.accent : priorityColors[p as keyof typeof priorityColors]}]}
onPress={() => setPriorityFilter(p)}>
<Text style={[styles.filterBtnText, {color: priorityFilter === p ? '#fff' : theme.subText}]}>
{p === 'all' ? '全部' : p === 'high' ? '高' : p === 'medium' ? '中' : '低'}
</Text>
</TouchableOpacity>
))}
</View>
</View>
遍历生成按钮
和状态筛选一样,用 map 方法遍历四个筛选值生成按钮。这种数据驱动的方式让代码更简洁。
类型断言
as PriorityFilter[] 告诉 TypeScript 数组元素的类型。p as keyof typeof priorityColors 告诉 TypeScript 这个 p 可以作为 priorityColors 对象的键。这些类型断言是为了让编译器满意。
按钮背景色的特殊处理
优先级筛选按钮的背景色比状态筛选复杂一些:
style={[styles.filterBtn, priorityFilter === p && {backgroundColor: p === 'all' ? theme.accent : priorityColors[p as keyof typeof priorityColors]}]}
条件逻辑
这里有两层条件:
- 首先判断按钮是否被选中
priorityFilter === p - 如果选中,再判断是"全部"还是具体的优先级
"全部"按钮的颜色
"全部"按钮选中时用主题强调色 theme.accent,因为它没有对应的优先级颜色。
优先级按钮的颜色
高、中、低优先级按钮选中时用各自的优先级颜色。这样用户一眼就能看出当前筛选的是什么优先级。
颜色与信息的统一
优先级筛选按钮的颜色和任务卡片上的优先级颜色是一致的:
<View style={[styles.priorityBar, {backgroundColor: priorityColors[item.priority]}]} />
视觉一致性
任务卡片左侧有一个彩色条表示优先级。筛选按钮选中时的颜色和这个彩色条是同一套颜色。这种一致性让用户能建立起"红色 = 高优先级"的心理模型。
信息的强化
当用户点击红色的"高"按钮时,列表里只剩下左侧有红色条的任务。颜色在筛选按钮和任务卡片之间形成了呼应,强化了筛选的效果。
筛选逻辑的实现
优先级筛选的逻辑很简单:
const filteredTasks = tasks.filter(task => {
const matchesSearch = task.title.toLowerCase().includes(searchText.toLowerCase());
const matchesFilter = filter === 'all' || (filter === 'active' && !task.completed) || (filter === 'completed' && task.completed);
const matchesPriority = priorityFilter === 'all' || task.priority === priorityFilter;
const matchesCategory = categoryFilter === 'all' || task.category === categoryFilter;
return matchesSearch && matchesFilter && matchesPriority && matchesCategory;
});
matchesPriority 的逻辑
const matchesPriority = priorityFilter === 'all' || task.priority === priorityFilter;
这是一个或运算:
- 如果
priorityFilter === 'all',所有任务都匹配 - 否则,只有优先级等于筛选值的任务才匹配
简洁的判断
优先级筛选比状态筛选简单,因为任务的 priority 字段直接就是 'high'、'medium' 或 'low',可以直接和筛选值比较。状态筛选需要根据 completed 布尔值来判断。
多重筛选的组合
优先级筛选可以和其他筛选条件组合使用:
return matchesSearch && matchesFilter && matchesPriority && matchesCategory;
组合的威力
用户可以同时使用多个筛选条件。比如:
- 搜索"学习" + 筛选"高优先级" = 找到所有高优先级的学习相关任务
- 筛选"待办" + 筛选"高优先级" = 找到所有未完成的高优先级任务
筛选的独立性
每个筛选条件是独立的,改变一个不会影响其他的。用户可以先设置优先级筛选,再设置状态筛选,顺序不影响结果。
筛选按钮的布局
优先级筛选按钮和状态筛选按钮使用相同的样式:
filterContainer: {marginBottom: 8},
filterGroup: {flexDirection: 'row', gap: 8},
filterBtn: {paddingHorizontal: 12, paddingVertical: 6, borderRadius: 16, backgroundColor: 'rgba(255,255,255,0.1)'},
filterBtnText: {fontSize: 12},
视觉统一
两组筛选按钮的大小、形状、间距都一样,看起来是一个整体。只有颜色不同,优先级按钮选中时会显示对应的优先级颜色。
位置安排
在我们的应用中,状态筛选在上,优先级筛选在下。这个顺序是有讲究的,状态(待办/已完成)是更基本的分类,优先级是在此基础上的细分。
未选中状态的视觉处理
未选中的按钮是什么样的?
style={[styles.filterBtn, priorityFilter === p && {...}]}
默认背景
未选中时只应用 styles.filterBtn 的样式,背景是 rgba(255,255,255,0.1),一个很淡的半透明白色。
文字颜色
{color: priorityFilter === p ? '#fff' : theme.subText}
未选中时文字颜色是 theme.subText,比较低调的灰色。
视觉层次
选中的按钮有鲜艳的背景色和白色文字,非常醒目。未选中的按钮背景淡、文字灰,视觉上退后。这种对比让用户一眼就能看出当前选中的是哪个。
优先级筛选的使用场景
什么时候用户会用优先级筛选?
处理紧急任务
早上开始工作时,先筛选高优先级任务,看看今天有哪些必须完成的事情。
填补碎片时间
有 10 分钟空闲时间,筛选低优先级任务,找一个简单的任务快速完成。
回顾和调整
周末回顾时,筛选各个优先级,看看任务分布是否合理,是不是高优先级任务太多了。
与统计数据的关系
统计页面显示各优先级的任务数量:
<View style={styles.priorityStats}>
<View style={styles.priorityStatItem}>
<View style={[styles.priorityDot, {backgroundColor: priorityColors.high}]} />
<Text style={[styles.priorityStatText, {color: theme.text}]}>高优先级</Text>
<Text style={[styles.priorityStatCount, {color: theme.subText}]}>{tasks.filter(t => t.priority === 'high').length}</Text>
</View>
<View style={styles.priorityStatItem}>
<View style={[styles.priorityDot, {backgroundColor: priorityColors.medium}]} />
<Text style={[styles.priorityStatText, {color: theme.text}]}>中优先级</Text>
<Text style={[styles.priorityStatCount, {color: theme.subText}]}>{tasks.filter(t => t.priority === 'medium').length}</Text>
</View>
<View style={styles.priorityStatItem}>
<View style={[styles.priorityDot, {backgroundColor: priorityColors.low}]} />
<Text style={[styles.priorityStatText, {color: theme.text}]}>低优先级</Text>
<Text style={[styles.priorityStatCount, {color: theme.subText}]}>{tasks.filter(t => t.priority === 'low').length}</Text>
</View>
</View>
统计不受筛选影响
统计数据是基于原始的 tasks 数组计算的,不受筛选影响。用户筛选高优先级任务时,仍然能在统计页面看到所有优先级的任务数量。
颜色的一致性
统计页面的优先级圆点也使用 priorityColors,和筛选按钮、任务卡片保持一致。整个应用中,红色永远代表高优先级。
筛选结果为空的处理
如果筛选后没有匹配的任务,会显示空状态组件。可以根据筛选条件显示更具体的提示:
const getEmptyMessage = () => {
if (priorityFilter === 'high') return '没有高优先级任务';
if (priorityFilter === 'medium') return '没有中优先级任务';
if (priorityFilter === 'low') return '没有低优先级任务';
return '暂无任务';
};
积极的提示
"没有高优先级任务"可以是一个好消息,说明紧急的事情都处理完了。可以配上一个庆祝的图标让用户感觉良好。
筛选按钮的可访问性
为优先级筛选按钮添加可访问性支持:
<TouchableOpacity
key={p}
style={[styles.filterBtn, priorityFilter === p && {backgroundColor: p === 'all' ? theme.accent : priorityColors[p as keyof typeof priorityColors]}]}
onPress={() => setPriorityFilter(p)}
accessibilityRole="button"
accessibilityState={{selected: priorityFilter === p}}
accessibilityLabel={p === 'all' ? '显示所有优先级' : p === 'high' ? '筛选高优先级任务' : p === 'medium' ? '筛选中优先级任务' : '筛选低优先级任务'}
>
颜色不是唯一的信息载体
虽然我们用颜色区分优先级,但按钮上也有文字"高"、“中”、“低”。这对色盲用户很重要,他们可能分不清红色和绿色,但能看到文字。
性能考虑
每次筛选条件变化,filteredTasks 都会重新计算:
const filteredTasks = tasks.filter(task => {
// 四个筛选条件
});
计算量
对于每个任务,需要检查四个条件。如果有 100 个任务,就是 400 次比较。这个计算量很小,JavaScript 瞬间就能完成。
何时需要优化
如果任务列表有几千条,可以考虑用 useMemo 缓存筛选结果:
const filteredTasks = useMemo(() => {
return tasks.filter(task => {
// 筛选逻辑
});
}, [tasks, searchText, filter, priorityFilter, categoryFilter]);
只有当依赖项变化时才重新计算。不过对于大多数应用,这种优化是不必要的。
小结
优先级筛选让用户能快速聚焦到特定重要程度的任务。它的特点是用颜色传达信息,红黄绿的交通灯系统让用户一眼就能理解。
实现要点:
- 用
TypeScript联合类型定义筛选值,包含'all'和三个优先级 - 选中时按钮背景色变成对应的优先级颜色,"全部"用主题强调色
- 筛选逻辑简单,直接比较任务的
priority字段和筛选值 - 颜色在筛选按钮、任务卡片、统计页面保持一致
好的优先级筛选应该让用户"看颜色就知道重要程度,点一下就能聚焦"。颜色是最直观的信息载体,善用它能大大提升用户体验。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐
所有评论(0)