Раскрывающийся список - это наиболее часто используемый шаблон пользовательского интерфейса для сжатия сложных функций в небольшом пространстве. В основном он состоит из триггера и меню. Варианты включают триггер в качестве входных данных, который также действует как поиск элементов в раскрывающемся меню. Вы также можете найти раскрывающиеся меню, которые выглядят и действуют как подсказки, а внутри них - другие раскрывающиеся списки.
Анатомия раскрывающегося списка
+--------------------------------------+ | +--------> Dropdown | +--------------------------------+ | | | | | | | +-----------> DropTrigger | | | | | +--------------------------------+ | | | | +--------------------------------+ | | | +-----------> DropMenu | | +----------------------------+ | | | | | | | | | | | | | | | | +----------------------------+ | | | | +----------------------------+ | | | | | | | | | | | +-------------> DropItem | | +----------------------------+ | | | | | | | +--------------------------------+ | | | +--------------------------------------+
Подход React с использованием ref
Когда я начинал изучать React, мне всегда было сложно разобраться в раскрывающемся списке. Существует множество реализаций вне там, но ни одна из них не справляется со сложной настройкой. Я должен признать, что не пробовал ни одного раскрывающегося списка в новых фреймворках пользовательского интерфейса, но когда React был в версии 0.9, там было еще меньше возможностей для выбора.
Итак, я реализовал свой собственный:
<Dropdown trigger={this.renderTrigger()} ref="dropdown">
<a onClick={this.onSelect.bind(this, 1)}>Option 1</a>
<a onClick={this.onSelect.bind(this, 2)}>Option 2</a>
</Dropdown>
...
onSelect(option) {
this.props.onSelect(option);
this.refs.dropdown.close()
}
Но закрытие раскрывающегося списка стало более повторяющейся задачей, когда мы добавили доступ к этому компоненту, зафиксировав фокус при его открытии. Итак, я спросил себя, не может ли быть более простого способа?
Возьмите два: используйте контекст
Мы можем использовать анатомию раскрывающегося списка, чтобы составить его в React. Dropdown acts в качестве менеджера по расположению, размещая дочерние элементы в нужных местах и создавая контекст, который будет использовать DropItem. Он добавляет поведение по умолчанию, такое как закрытие меню при щелчке вне раскрывающегося списка, и гарантирует, что триггер будет переключать видимость раскрывающегося меню при щелчке по нему. Он может обеспечивать согласованность CSS, а также применять темы, но это выходит за рамки этой публикации.
Чтобы идентифицировать каждый составляющий блок Dropdown, я создал несколько компонентов-заполнителей, чтобы упростить настройку раскрывающегося списка для отображения различных элементов в качестве триггера или внутри меню, что сделало его более универсальным. Эти компоненты не должны влиять на рендеринг Dropdown и не должны добавлять дополнительную разметку. Я также создал компонент-декоратор для управления поведением выпадающего элемента.
DropMenu, как и DropTrigger, - это просто заполнитель для Dropdown component, чтобы определить и разместить его дочерние элементы в нужном месте. Нет варианта использования, когда эти компоненты использовались бы вне Dropdown. Семантически не имеет смысла повторно использовать их где-либо еще.
Это позволит отображать настраиваемые триггеры для компонентов Select, например: отображать значение Select или количество выбранных элементов Multiselect. Вы также можете добавить другую разметку в DropMenu, например, ввод для поиска, чтобы реализовать функциональность элементов поиска и т. Д.
DropItem будет использовать контекст Dropdown, чтобы закрыть раскрывающийся список, если необходимо, на основе свойства closeOnClick. Он отправит onClick опору своим дочерним элементам, чтобы добавить к нему корневой / оборачивающий элемент. Это можно рассматривать как тесную связь, но у DropItem нет причин выходить за пределы Dropdown.
Это решает проблему вызова дочерним методом родительского метода с использованием ссылки. Использование контекста - лучший подход для создания элегантного кода, который четко разделяет проблемы.
Спасибо, что прочитали. Всегда приветствуются рекомендации, комментарии и твиты.
Скоро будет доступен репозиторий с некоторыми примерами, чтобы доказать, как это решение может работать в различных раскрывающихся реализациях