Фильтрация дерева

Фильтрация дерева — одна из ключевых возможностей компонента ElTree в библиотеке Element Plus, позволяющая пользователям динамически искать и отображать узлы на основе заданного критерия. Это особенно актуально при работе с большими иерархическими структурами данных, где необходимо скрывать лишние ветви и выделять релевантные элементы.


Подготовка данных для фильтрации

Данные для дерева должны быть организованы в виде массива объектов с обязательными свойствами:

  • id — уникальный идентификатор узла.
  • label — текст, который отображается в дереве.
  • children — массив дочерних узлов (если есть).

Пример структуры данных:

const treeData = [
  {
    id: 1,
    label: 'Фрукты',
    children: [
      { id: 11, label: 'Яблоки' },
      { id: 12, label: 'Апельсины' }
    ]
  },
  {
    id: 2,
    label: 'Овощи',
    children: [
      { id: 21, label: 'Морковь' },
      { id: 22, label: 'Брокколи' }
    ]
  }
];

Ключевой момент: фильтрация работает только с текущими данными дерева, поэтому любые динамические изменения в массиве treeData должны быть отражены в компоненте через реактивность Vue.


Методы фильтрации

Компонент ElTree предоставляет метод filter, который позволяет задавать функцию фильтрации:

<el-tree
  :data="treeData"
  :props="{ children: 'children', label: 'label' }"
  ref="treeRef"
>
</el-tree>

В JavaScript-файле:

const treeRef = ref(null);

const filterNode = (value, data) => {
  if (!value) return true;
  return data.label.toLowerCase().includes(value.toLowerCase());
};

const applyFilter = (searchText) => {
  treeRef.value.filter(searchText);
};

Особенности работы метода filter:

  • Принимает строку поиска или функцию, которая возвращает true для узлов, которые должны остаться видимыми.
  • Автоматически скрывает узлы, не соответствующие фильтру, и все их дочерние элементы.
  • Родительские узлы, содержащие совпадающие дочерние элементы, остаются видимыми, чтобы сохранять структуру дерева.

Динамическая фильтрация

Для реализации интерактивного поиска часто используется связка с v-model:

<el-input
  v-model="searchText"
  placeholder="Введите название"
  @input="applyFilter(searchText)"
></el-input>

<el-tree
  :data="treeData"
  :props="{ children: 'children', label: 'label' }"
  ref="treeRef"
></el-tree>
const searchText = ref('');

watch(searchText, (newVal) => {
  treeRef.value.filter(newVal);
});

Преимущество такого подхода — мгновенное обновление дерева при вводе текста, без необходимости ручного обновления состояния.


Фильтрация с кастомными критериями

Метод filter не ограничен простой проверкой строки. Можно фильтровать по любому полю узла или по сложной логике:

const customFilter = (value, data) => {
  if (!value) return true;
  // Показываем только узлы с id больше 10, если строка поиска совпадает
  return data.label.includes(value) && data.id > 10;
};

treeRef.value.filter(customFilter);

Ключевой момент: функция фильтрации вызывается для каждого узла, включая дочерние элементы. Для больших деревьев рекомендуется оптимизировать логику, чтобы избежать падения производительности.


Особенности отображения после фильтрации

  1. Скрытие узлов — узлы, не удовлетворяющие фильтру, становятся невидимыми, но не удаляются из данных. Это позволяет сохранять целостность структуры дерева.
  2. Выделение совпадений — можно дополнительно подсвечивать совпавшие элементы с помощью пользовательских классов через слот default.
  3. Сброс фильтрации — вызов filter('') восстанавливает исходное дерево.

Пример с подсветкой:

<el-tree
  :data="treeData"
  :props="{ children: 'children', label: 'label' }"
  ref="treeRef"
>
  <template #default="{ node, data }">
    <span :class="{ highlight: data.label.includes(searchText) }">{{ data.label }}</span>
  </template>
</el-tree>
.highlight {
  background-color: yellow;
}

Фильтрация с асинхронной загрузкой

Для деревьев с ленивой загрузкой (lazy):

  • Фильтрация может выполняться только на уже загруженных узлах.
  • Для полного поиска по всем уровням необходимо динамически загружать дочерние элементы, совпадающие с фильтром.

Пример:

const loadNode = (node, resolve) => {
  setTimeout(() => {
    if (node.level === 0) {
      resolve([
        { id: 1, label: 'Фрукты', isLeaf: false },
        { id: 2, label: 'Овощи', isLeaf: false }
      ]);
    } else if (node.data.label === 'Фрукты') {
      resolve([{ id: 11, label: 'Яблоки' }, { id: 12, label: 'Апельсины' }]);
    } else {
      resolve([]);
    }
  }, 500);
};

<el-tree
  :data="[]"
  :props="{ children: 'children', label: 'label', isLeaf: 'isLeaf' }"
  :load="loadNode"
  lazy
  ref="treeRef"
></el-tree>

В такой схеме фильтрация требует дополнительно загрузить все возможные узлы, чтобы функция filter могла проверить соответствие каждого элемента.


Фильтрация дерева в Element Plus предоставляет гибкие возможности для поиска, скрытия и выделения узлов. Благодаря методу filter и поддержке кастомных функций можно реализовать как простой поиск по строке, так и сложные условия на основе любых данных узла. В сочетании с реактивностью Vue и слотами для кастомного рендеринга, фильтрация становится мощным инструментом для создания интерактивных интерфейсов с иерархическими структурами.