Select и множественный выбор

Slim.js предоставляет лёгкий и производительный способ управления DOM через декларативный синтаксис. Одной из ключевых задач в интерфейсах является работа с элементами <select> и поддержка множественного выбора. Slim.js облегчает синхронизацию данных с UI и позволяет управлять списками опций динамически.

Создание простого select

Для создания стандартного <select> в Slim.js используется привязка к массиву данных с помощью атрибута each. Например:

class SimpleSelect extends Slim {
  constructor() {
    super();
    this.options = [
      { id: 1, name: 'Красный' },
      { id: 2, name: 'Зелёный' },
      { id: 3, name: 'Синий' }
    ];
    this.selected = null;
  }

  onSelectChange(e) {
    this.selected = e.target.value;
    console.log('Выбран:', this.selected);
  }
}

Slim.tag('simple-select', SimpleSelect);
<simple-select>
  <SELECT on-change="onSelectChange">
    <option each="option in options" value="{{option.id}}">
      {{option.name}}
    </option>
  </select>
</simple-select>

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

  • each="option in options" создаёт опции автоматически по массиву объектов.
  • {{option.name}} — связывание текста опции с полем объекта.
  • Атрибут on-change позволяет отлавливать изменения выбора и обновлять состояние компонента.

Поддержка множественного выбора

Для включения множественного выбора необходимо добавить атрибут multiple к <select> и использовать массив для хранения выбранных значений.

class MultiSelect extends Slim {
  constructor() {
    super();
    this.options = [
      { id: 1, name: 'Python' },
      { id: 2, name: 'JavaScript' },
      { id: 3, name: 'Java' }
    ];
    this.selected = [];
  }

  onSelectChange(e) {
    const selectedOptions = Array.FROM(e.target.selectedOptions).map(o => o.value);
    this.selected = selectedOptions;
    console.log('Выбрано:', this.selected);
  }
}

Slim.tag('multi-select', MultiSelect);
<multi-select>
  <SELECT multiple on-change="onSelectChange">
    <option each="option in options" value="{{option.id}}">
      {{option.name}}
    </option>
  </select>
</multi-select>

Особенности множественного выбора:

  • Значение selected становится массивом, а не одиночным значением.
  • Метод Array.FROM(e.target.selectedOptions) позволяет получить все выбранные элементы.
  • При динамическом обновлении массива options Slim.js автоматически пересоздаёт DOM, сохраняя выбранные элементы, если они присутствуют в новом массиве.

Динамическое управление опциями

Slim.js позволяет не только рендерить статические опции, но и динамически изменять их содержимое.

class DynamicSelect extends Slim {
  constructor() {
    super();
    this.options = [];
    this.selected = null;
  }

  connectedCallback() {
    setTimeout(() => {
      this.options = [
        { id: 'a', name: 'Опция A' },
        { id: 'b', name: 'Опция B' },
        { id: 'c', name: 'Опция C' }
      ];
    }, 1000);
  }

  onSelectChange(e) {
    this.selected = e.target.value;
  }
}

Slim.tag('dynamic-select', DynamicSelect);
  • Опции появляются через секунду после подключения компонента, демонстрируя реактивность Slim.js.
  • Любое изменение массива options автоматически обновляет DOM.
  • Slim.js использует оптимизированный diff, чтобы минимально перерисовывать <option>.

Привязка к объектам и сложные значения

Можно использовать сложные объекты в качестве значений опций и связывать их напрямую с компонентом:

class ObjectSelect extends Slim {
  constructor() {
    super();
    this.options = [
      { id: 1, name: 'Alice', age: 25 },
      { id: 2, name: 'Bob', age: 30 }
    ];
    this.selected = null;
  }

  onSelectChange(e) {
    const selectedId = parseInt(e.target.value, 10);
    this.selected = this.options.find(opt => opt.id === selectedId);
  }
}

Slim.tag('object-select', ObjectSelect);
  • В массиве options хранятся объекты, а не только строки.
  • Событие change позволяет найти выбранный объект и сохранить его полностью, а не только значение поля.

Реактивная синхронизация выбранных значений

Slim.js поддерживает двустороннюю привязку через bind. Для множественного выбора можно использовать следующее решение:

<select multiple bind="selected">
  <option each="option in options" value="{{option.id}}">
    {{option.name}}
  </option>
</select>
  • Любое изменение в selected автоматически обновляет UI.
  • При изменении выбора пользователем массив selected обновляется автоматически.

Дополнительные возможности

  • Группы опций (<optgroup>): можно динамически рендерить группы, используя вложенный each.
  • Условные опции: Slim.js поддерживает if внутри <option>, позволяя фильтровать опции на лету.
  • Стилизация: можно использовать классы и стили через привязку атрибутов class="{{…}}" для выделения выбранных опций.

Эта гибкость делает Slim.js мощным инструментом для управления <select> элементами с множественным выбором, динамическими данными и сложными объектами.