v-for="t in todos.filter(...)"——每次渲"> v-for="t in todos.filter(...)"——每次渲"> v-for="t in todos.filter(...)"——每次渲">
Vue 词条目录
前端Wiki/Vue/进阶/条件与列表渲染

列表过滤与排序

列表过滤与排序的正确姿势:不要在模板里写 v-for="t in todos.filter(...)"——每次渲染都重新过滤;用 computed 派生一份「过滤并排序后的列表」,依赖变化才重算。

排序特别注意:直接 list.sort() 会改动原数组;用 [...list].sort() 先拷贝再排,避免修改源数据引发意料外的更新。

  • 过滤/排序都用 computed 派生,不要在 v-for 里写方法调用
  • [...arr].sort() 先拷贝再排,不污染原数组
  • 升序降序切换:computed 内根据 sortKey 与 order 计算
HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>列表过滤与排序</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
  <div id="app">
    <input v-model="q" placeholder="按名称过滤">
    <button @click="order = order === 1 ? -1 : 1">切换排序</button>
    <ul>
      <li v-for="p in filtered" :key="p.id">{{ p.name }} - {{ p.price }} 元</li>
    </ul>
  </div>

<script>
  const { createApp, ref, computed } = Vue;
  createApp({
    setup() {
      const products = ref([
        { id: 1, name: '苹果', price: 6 },
        { id: 2, name: '香蕉', price: 4 },
        { id: 3, name: '樱桃', price: 20 }
      ]);
      const q = ref('');
      const order = ref(1);    // 1 升序 -1 降序

      // 过滤 + 排序都由 computed 完成,自动缓存
      const filtered = computed(() => {
        const list = products.value.filter(p => p.name.includes(q.value));
        return [...list].sort((a, b) => (a.price - b.price) * order.value);
      });

      return { q, order, filtered };
    }
  }).mount('#app');
</script>
</body>
</html>
本节要点列表加工交给 computed:过滤+排序一次派生,[...arr] 先拷贝再 sort 不动原数据。