如何在Vuetify的数据表格中使用“自定义过滤器”属性?或者如何创建一个按标题筛选的自定义过滤器?

33
发布日期的截至目前,我找不到任何有关在数据表中使用“自定义过滤器”属性的文档。
我只想创建一个自定义过滤器来通过标题过滤我的数据表。我有一个下拉菜单,当用户单击其中一项选项时,它将以一个特定的标题来筛选列表。
例如: 下拉菜单选项: 食品类型:水果、肉类、蔬菜
  1. 大白菜 (蔬菜)
  2. 猪肉 (肉类)
  3. 鸡腿 (肉类)
  4. 西瓜 (水果)
如果我选择肉类,它应该只显示给我猪肉和鸡腿。

你弄明白了吗?我正在寻找相同的信息。 - sterling
嘿,Sterling,抱歉回复晚了。在我有机会解决它之前,我被撤职了。所以我不能说我找到了解决方案,但我相信下面的答案之一应该能帮助你。 :) - alwayshungryleh
3个回答

45

查看 Github 上的代码1,看起来 customFilter 属性用于覆盖默认方法,该方法确定如何将 filter 属性应用于表格中的项目。

默认的 customFilter 方法将 filter 函数应用于每个项目对象的每个属性名称,并过滤掉不包含通过筛选器的任何一个属性名称的项目:

customFilter: {
  type: Function,
  default: (items, search, filter) => {
    search = search.toString().toLowerCase()
    return items.filter(i => (
      Object.keys(i).some(j => filter(i[j], search))
    ))
  }
},
如果您想要防止任何列被包含在筛选器中,或者有特定行始终要防止被过滤掉,可以覆盖此函数。请注意,该方法还依赖于必须是字符串的“search”属性。
话虽如此,您实际上不需要使用该属性来做您想做的事情。您只需创建一个计算属性来根据下拉列表值过滤项目,并将该计算属性作为“items”属性传递。
以下是示例:
new Vue({
  el: '#app',
  data() {
    return {
      food: [
        { name: 'Bakchoi', type: 'vegetable', calories: 100 },
        { name: 'Pork', type: 'meat', calories: 200 },
        { name: 'Chicken Thigh', type: 'meat', calories: 300 },
        { name: 'Watermelon', type: 'fruit', calories: 10 },
      ],
      headers: [
        { text: 'Name', align: 'left', value: 'name' },
        { text: 'Food Type', align: 'left', value: 'type' }, 
        { text: 'Calories', align: 'left', value: 'calories' },
      ],
      foodType: null,
    };
  },
  computed: {
    filteredItems() {
      return this.food.filter((i) => {
        return !this.foodType || (i.type === this.foodType);
      })
    }
  }
})
<script src="https://unpkg.com/vue@2.4.2/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify@0.15.2/dist/vuetify.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify@0.15.2/dist/vuetify.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons">

<div id="app">
  <v-app>  
    <v-select 
      label="Food Type" 
      :items="['vegetable', 'meat', 'fruit']"
      v-model="foodType"
    ></v-select>
    
    <v-data-table 
      :headers="headers"
      :items="filteredItems"
      hide-actions
    >
      <template slot="items" scope="{ item }">
        <td>{{ item.name }}</td>
        <td>{{ item.type }}</td>
        <td>{{ item.calories }}</td>
      </template>
    </v-data-table>
  </v-app>
</div>


  1. 这个答案是在Vuetify版本为v0.15.2时编写的。 该组件在该版本下的源代码可以在此处找到

8
使用自定义计算属性和自定义过滤器有略微不同的行为。如果您使用自定义计算属性并且没有结果,数据表将显示无数据插槽。如果您使用自定义过滤器并且没有结果,则数据表将显示无结果插槽。这种差异通常很重要。 - K Johnson
@KJohnson 您可以通过使用“无数据”插槽并根据缺少数据的来源或计算属性过滤器自定义消息来解决差异。 - Abion47
1
链接已损坏。 - Scott Baker

13

您也可以使用自定义过滤器方法,像这样做,我已将搜索限制为类型字段。

new Vue({
    el: '#app',
    data() {
        return {
            food: [
                { name: 'Bakchoi', type: 'vegetable', calories: 100 },
                { name: 'Pork', type: 'meat', calories: 200 },
                { name: 'Chicken Thigh', type: 'meat', calories: 300 },
                { name: 'Watermelon', type: 'fruit', calories: 10 },
            ],
            headers: [
                { text: 'Name', align: 'left', value: 'name' },
                { text: 'Food Type', align: 'left', value: 'type' },
                { text: 'Calories', align: 'left', value: 'calories' },
            ],
            search: '',

        };
    },
    methods: {
        customFilter(items, search, filter) {

            search = search.toString().toLowerCase()
            return items.filter(row => filter(row["type"], search));

        }
    }
})
<script src="https://unpkg.com/vue@2.4.2/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify@0.15.2/dist/vuetify.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify@0.15.2/dist/vuetify.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons">

<div id="app">
    <v-app>
        <v-select
                label="Food Type"
                :items="['vegetable', 'meat', 'fruit']"
                v-model="search"
        ></v-select>

        <v-data-table
                :headers="headers"
                :items="food"
                :search="search"
                :custom-filter="customFilter"
                hide-actions
        >
            <template slot="items" scope="{ item }">
                <td>{{ item.name }}</td>
                <td>{{ item.type }}</td>
                <td>{{ item.calories }}</td>
            </template>
        </v-data-table>
    </v-app>
</div>


使用这种方法将会调用 customFilter 方法两次(参见:https://codepen.io/yosafatade/pen/axMooM 并打开控制台窗口)。如果您有大量数据,这将是一个性能问题。 - yosafatade
1
我在Github上创建了一个关于我上面提到的问题的问题:https://github.com/vuetifyjs/vuetify/issues/7090你可以看到vuetify v-1的解决方法:https://codepen.io/yosafatade/pen/gyEKeW - yosafatade

2
在我的情况下,我有两种不同的筛选方式,即搜索栏和下拉菜单。我尝试使用custom-filter来处理它们,但是它没有起作用,所以我想出了另一种方法。
<v-text-field v-model="search" label="Label"></v-text-field>
<v-select
    v-model="select"
    :items="food"
    item-text="type"
    item-value="type"
    :label="Types"
    @change="filterFoodUsingDropDown"
>
</v-select>
<v-data-table
    :search="search"
    :headers="headers"
    :items="food"
    :custom-filter="filterFoodUsingSearchbar"
>

data() {
    return {
        food: [
            { name: 'Bakchoi', type: 'vegetable', calories: 100 },
            { name: 'Pork', type: 'meat', calories: 200 },
            { name: 'Chicken Thigh', type: 'meat', calories: 300 },
            { name: 'Watermelon', type: 'fruit', calories: 10 },
        ],
        headers: [
            { text: 'Name', align: 'left', value: 'name' },
            { text: 'Food Type', align: 'left', value: 'type' },
            { text: 'Calories', align: 'left', value: 'calories' },
        ],
        search: '',
        select: '',
    };
},
methods: {
    filterFoodUsingSearchbar(items, search, filter) {
            // Condition
    }
        
    filterFoodUsingDropDown() {
        if (this.select !== '') {
            // In this case I use vuex to store the original data of the 
               food so that all the data is still exist even we filtered it out
            this.food = this.$store.state.food.filter((item) => item.type === this.select)
        }
    }

1
正确的方法是使用:custom-key-filter选项...即 :custom-key-filter="{'myHeaderKey': myHeaderKeyFilter}" 然而,在Vuetify bug (10815)修复之前,这个答案似乎是最好的选择。 - A-Diddy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接