Render functions

В Element Plus render-функции предоставляют гибкий способ создания компонентов и управления их разметкой программно, минуя традиционные шаблоны template. Это особенно полезно, когда требуется динамическая генерация сложных структур или управление поведением компонентов на основе условий во время выполнения.

Render-функция — это обычная функция JavaScript, которая возвращает VNode (виртуальный узел), описывающий структуру DOM. В Element Plus и Vue 3 используется функция h из Vue для создания этих виртуальных узлов.

import { h } from 'vue';
import { ElButton } from 'element-plus';

export default {
  setup() {
    return () =>
      h(ElButton, { type: 'primary', onClick: () => alert('Clicked!') }, 'Нажми меня');
  }
};

Здесь ключевые моменты:

  • h принимает три аргумента: тип компонента, объект с props/атрибутами, и дочерние элементы.
  • Можно использовать любые компоненты Element Plus, передавая им props так же, как в шаблонах.
  • Дочерние элементы могут быть строками, массивами VNode или другими вызовами h, что позволяет строить иерархические структуры.

Динамическая генерация компонентов

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

import { h } from 'vue';
import { ElButton } from 'element-plus';

const types = ['primary', 'success', 'warning', 'danger'];

export default {
  setup() {
    return () =>
      h('div', {}, types.map(type =>
        h(ElButton, { type, style: { margin: '0 8px' } }, type)
      ));
  }
};

Преимущества такого подхода:

  • Полная динамическая настройка пропсов.
  • Отсутствие необходимости создавать отдельные шаблоны для каждой вариации.
  • Возможность управления структурой DOM через обычный JavaScript.

Использование слотов через render-функции

В Element Plus компоненты часто имеют слоты, например ElTable, ElForm, ElSelect. Render-функции позволяют передавать слоты программно с помощью объекта slots:

import { h } from 'vue';
import { ElTable, ElTableColumn } from 'element-plus';

const data = [
  { name: 'Иван', age: 28 },
  { name: 'Мария', age: 32 }
];

export default {
  setup() {
    return () =>
      h(ElTable, { data }, {
        default: () => [
          h(ElTableColumn, {
            prop: 'name',
            label: 'Имя',
            width: 120
          }),
          h(ElTableColumn, {
            prop: 'age',
            label: 'Возраст',
            width: 80
          })
        ]
      });
  }
};

Особенности работы со слотами через render-функции:

  • Каждый слот передается как функция, возвращающая VNode.
  • Можно создавать условные слоты или изменять их содержимое динамически.
  • Полная совместимость с компонентами Element Plus.

Передача событий и реактивных данных

В render-функциях доступ к событиям и реактивным данным Vue сохраняется полностью. Можно использовать ref и reactive для управления состоянием:

import { h, ref } from 'vue';
import { ElInput, ElButton } from 'element-plus';

export default {
  setup() {
    const inputValue = ref('');

    return () =>
      h('div', [
        h(ElInput, {
          modelValue: inputValue.value,
          'onUpdate:modelValue': val => inputValue.value = val,
          placeholder: 'Введите текст'
        }),
        h(ElButton, {
          type: 'primary',
          onClick: () => console.log(inputValue.value)
        }, 'Отправить')
      ]);
  }
};

Ключевые моменты:

  • Связывание modelValue и onUpdate:modelValue заменяет директиву v-model.
  • Состояние реактивно, изменения автоматически обновляют интерфейс.
  • События компонентов Element Plus передаются так же, как в шаблонах.

Комбинирование с условной логикой и циклами

Render-функции позволяют полностью использовать преимущества JavaScript для условного рендеринга:

import { h, ref } from 'vue';
import { ElButton } from 'element-plus';

export default {
  setup() {
    const loggedIn = ref(false);

    return () =>
      h('div', [
        loggedIn.value
          ? h(ElButton, { type: 'success' }, 'Выйти')
          : h(ElButton, { type: 'primary' }, 'Войти')
      ]);
  }
};

Преимущества:

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

Использование render-функций для кастомных компонентов Element Plus

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

import { h } from 'vue';
import { ElTable, ElTableColumn } from 'element-plus';

const data = [
  { name: 'Алексей', score: 95 },
  { name: 'Ольга', score: 82 }
];

export default {
  setup() {
    return () =>
      h(ElTable, { data }, {
        default: () => [
          h(ElTableColumn, {
            prop: 'name',
            label: 'Имя'
          }),
          h(ElTableColumn, {
            prop: 'score',
            label: 'Баллы',
            // Пользовательский рендер через render-функцию
            vSlots: {
              default: ({ row }) => h('span', {
                style: { color: row.score > 90 ? 'green' : 'orange' }
              }, row.score)
            }
          })
        ]
      });
  }
};

Особенности:

  • Полный контроль над внешним видом ячеек таблицы.
  • Возможность применять динамическую стилизацию и вычислять значения на лету.
  • Использование render-функций совместимо с API слотов Vue 3 и Element Plus.

Render-функции в Element Plus позволяют сочетать мощь реактивного Vue 3 с гибкостью программной генерации компонентов, обеспечивая полную свободу в построении интерфейсов и логики компонентов.