在 Vue 3 中使用 Computed 创建搜索输入过滤器

Creating a Search Input Filter with Computed in Vue 3

我已通过 this guide 创建搜索过滤器输入字段,但无法弄清楚如何在 v-model.

中正确实施 computed

我已将指南中的代码转换为:

<template>
  <div id="table-cms" class="table-cms">
    <input class="search-field textfield-closed" type="search" placeholder="Search" v-model="filter">
    <p>{{ filter }}</p>
    <p>{{ state.array }}</p>
  </div>
</template>


<script setup>
import {computed, reactive} from "vue";

const state = reactive({
    search: null,
    array: [
        {id: 1, title: 'Thanos', content: '123'},
        {id: 2, title: 'Deadpool', content: '456'},
        {id: 3, title: 'Batman', content: '789'}
    ]
})

const filter = computed({
    get() {
        console.log('check1')
        return state.search
    },
    set() {
        if (state.search) {
            console.log('check2a')
            return state.array.filter(item => {
                return state.search
                    .toLowerCase()
                    .split(" ")
                    .every(v => item.title.toLowerCase().includes(v))
            });
        } else {
            console.log('check2b')
            return state.array;
        }
    }
})
</script>

但是控制台显示:

check1
check2b
check2b
check2b
...

这意味着 computed 被执行但它没有进入 if (state.search) {}(实际过滤器)。显示 state.array 确实会呈现初始数组,但不会通过在输入字段中键入不同的标题来更新:

<p>{{ state.array }}</p>

渲染:

[
  {
    "id": 1,
    "title": "Thanos",
    "content": "123"
  },
  {
    "id": 2,
    "title": "Deadpool",
    "content": "456"
  },
  {
    "id": 3,
    "title": "Batman",
    "content": "789"
  }
]

我做错了什么?

您必须使用 state.search 作为输入的 v-model

<input class="search-field textfield-closed" type="search" placeholder="Search" v-model="state.search">

否则它将永远保持 null,因为它不会改变,这会导致代码跳过 if 语句。

此外,您的计算过滤器中不需要 setter。

<template>
    <div id="table-cms" class="table-cms">
        <input
            class="search-field textfield-closed"
            type="search"
            placeholder="Search"
            v-model="state.search"
        />
        <p>{{ state.array }}</p>
    </div>
</template>

<script setup>
import { computed, reactive } from "vue";

const state = reactive({
    search: null,
    array: [
        { id: 1, title: "Thanos", content: "123" },
        { id: 2, title: "Deadpool", content: "456" },
        { id: 3, title: "Batman", content: "789" },
    ],
});

const filter = computed(() => {
    if (state.search) {
        //console.log('check2a')
        return state.array.filter((item) => {
            return state.search
                .toLowerCase()
                .split(" ")
                .every((v) => item.title.toLowerCase().includes(v));
        });
    } else {
        console.log("check2b");
        return state.array;
    }
});
</script>