#请添加图片描述

案例开源地址: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]}]}

条件逻辑

这里有两层条件:

  1. 首先判断按钮是否被选中 priorityFilter === p
  2. 如果选中,再判断是"全部"还是具体的优先级

"全部"按钮的颜色

"全部"按钮选中时用主题强调色 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

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐