Как реализовать контекстное меню в таблице с позиционированием в зависимости от положения ячейки и экрана?
Что проверяют
Знаете ли вы системы координат браузера и умеете ли довести меню до рабочего состояния: у края экрана, в прокручиваемой таблице, с клавиатуры. Показать меню по contextmenu умеют все, отличает ответ логика переворота и закрытия. Следом спрашивают про доступность и готовые решения.
Как отвечать
Каркас:
- один обработчик на таблицу:
contextmenuвешается наtable, ячейка находится черезe.target.closest('td'), из неё берутся id строки и колонки.e.preventDefault()отменяет системное меню; - координаты в одной системе: меню с
position: fixedставится поclientXиclientYи сравнивается сwindow.innerWidthиinnerHeight. Для привязки к ячейке, например по кнопке «…», беритеcell.getBoundingClientRect(); - переворот и прижим: меню рендерится невидимым и измеряется. Не помещается снизу, открывается вверх от точки, не помещается справа, открывается влево. Затем координаты прижимаются к краям;
- обрезка контейнером: таблица в блоке с
overflow: autoобрежет абсолютно позиционированное меню. Его выносят в портал (createPortalвdocument.body) или в верхний слой через атрибутpopover; - закрытие: клик мимо по
pointerdown,Escape, прокрутка, изменение размеров окна, потеря фокуса; - доступность:
role="menu"иrole="menuitem", стрелки для навигации, возврат фокуса в ячейку после закрытия. Меню открывается и с клавиатуры, по Shift+F10 или клавише меню, и тогда позицию берут от ячейки в фокусе, а не от курсора.
В реальном проекте разумно взять Floating UI: middleware offset, flip и shift делают переворот и прижим, autoUpdate следит за прокруткой. Нативная альтернатива: CSS anchor positioning с position-try-fallbacks, но поддержку браузерами надо проверять.
Где спотыкаются
Смешивают системы координат: ставят pageY и сравнивают его с innerHeight. После прокрутки страницы меню уезжает за экран.
Измеряют меню, пока оно под display: none: offsetWidth равен нулю, и проверка границ ничего не делает.
Привязывают меню к DOM-узлу строки в виртуализированной таблице. При прокрутке узел переиспользуется под другую строку, и действие применяется не к той записи.