Задать вопрос
@rt_s23

Как реализовать фильтрацию на vue.js по нескольким параметрам одновременно?

У меня есть таблица, которая должна фильтроваться по всем полям, кроме даты.
Фильтрация должна быть в виде двух выпадающих списков и текстового поля:
- Выбор колонки, по которой будет фильтрация
- Выбор условия (равно, содержит, больше, меньше)
- Поле для ввода значения для фильтрации

Вот разметка:
<select v-model="column">
    <option value="name">Имя</option>
    <option value="count">Количество</option>
    <option value="distance">Расстояние</option>
  </select>
  <select 
    v-model="type"
   >
     <option value="equal">Равно</option>
     <option value="contains">Содержит</option>
     <option value="more">Больше</option>
     <option value="less">Меньше</option>
   </select>
   <input type="text" v-model="input" />
    <button class="table__button" @click="filterItems()">Отфильтровать</button>


Вот данные во vue.
data(){
      column: '',
      type: '',
      input: ''
}


А так выглядит json, который и нужно фильтровать, я получаю их и записываю в переменную:

[
	{
		"id": 1,
		"date": "2022-10-12T21:07:14.000Z",
		"name": "Утренний марафон",
		"count": 1,
		"distance": 1500,
		"createdAt": "2022-10-12T21:07:14.483Z",
		"updatedAt": "2022-10-12T21:07:14.483Z"
	},
	{
		"id": 2,
		"date": "2022-10-12T21:07:27.000Z",
		"name": "Дневной марафон",
		"count": 1,
		"distance": 4500,
		"createdAt": "2022-10-12T21:07:27.629Z",
		"updatedAt": "2022-10-12T21:07:27.629Z"
	},
	{
		"id": 3,
		"date": "2022-10-12T21:07:42.000Z",
		"name": "Вечерний марафон",
		"count": 1,
		"distance": 3000,
		"createdAt": "2022-10-12T21:07:42.379Z",
		"updatedAt": "2022-10-12T21:07:42.379Z"
	}
]


Непонятно, как объединить несколько параметров фильтрации одновременно.
  • Вопрос задан
  • 775 просмотров
Подписаться 2 Простой Комментировать
Решения вопроса 1
0xD34F
@0xD34F Куратор тега Vue.js
Сделаем описания столбцов, по которым допускается фильтрация, и способов фильтрации - имя, русифицированный вариант имени (чтобы показывать его в select'ах), и, у столбцов, тип данных:

data: () => ({
  filterColumns: [
    [     'name',        'имя', 'string' ],
    [    'count', 'количество', 'number' ],
    [ 'distance', 'расстояние', 'number' ],
  ],
  operations: [
    [    'equal',    'равно' ],
    [ 'contains', 'содержит' ],
    [  'greater',   'больше' ],
    [     'less',   'меньше' ],
  ],
  ...

Тип данных указываем потому, что значения различных типов сравниваются по-разному. Кстати, определим, как именно:

data: () => ({
  types: {
    string: {
      equal: (a, b) => a.toLowerCase() === b,
      contains: (a, b) => a.toLowerCase().includes(b),
      greater: (a, b) => a.toLowerCase() > b,
      less: (a, b) => a.toLowerCase() < b,
    },
    number: {
      equal: (a, b) => a === +b,
      contains: (a, b) => `${a}`.includes(b),
      greater: (a, b) => a > +b,
      less: (a, b) => a < +b,
    },
  },
  ...

На основе описаний столбцов и способов фильтрации создадим select'ы:

<select v-model="column">
  <option v-for="n in filterColumns" :value="n[0]">{{ n[1] }}</option>
</select>
<select v-model="operation">
  <option v-for="n in operations" :value="n[0]">{{ n[1] }}</option>
</select>

Наконец, собственно фильтрация - конечно же оформляем в виде вычисляемого свойства. По имени столбца, по которому надо фильтровать, извлекаем его описание и, соответственно, тип его данных. На основе типа данных и способа фильтрации извлекаем функцию фильтрации. Если таковая существует, и значение по которому надо фильтровать непустое, то выполняем фильтрацию, в противном случае возвращаем полные данные:

computed: {
  filteredItems() {
    const { items, column } = this;
    const type = this.filterColumns.find(n => n[0] === column)?.[2];
    const filterFn = this.types[type]?.[this.operation];
    const filterVal = this.filterVal.toLowerCase();

    return filterFn && filterVal
      ? items.filter(n => filterFn(n[column], filterVal))
      : items;
  },
  ...

https://jsfiddle.net/8df3z1un/1/
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы