Как динамически помещать переполненные элементы в раскрывающийся список

Постановка задачи

У меня простая динамическая панель навигации (количество элементов и текст можно изменить). Я хочу показать на экране первые X элементов, которые могут поместиться в одну строку, вместе с раскрывающимся списком «Показать больше», куда будут помещены все переполненные элементы, т. е. элементы, оставшиеся после размещения первых X элементов в строке.

Возможное решение

Я попытался добиться этого, вычислив ширину каждого элемента (ширина текста + отступ кнопки), проверив ширину экрана, а затем поместив только первые X элементов, общая ширина которых (плюс ширина кнопки «показать больше») равна меньше ширины экрана. Теперь самое сложное — вычислить ширину текста. Если мы сначала визуализируем все элементы, то легко получить визуализированную ширину каждого элемента, а затем мы можем выполнить приведенное выше вычисление, чтобы проверить, какие элементы умещаются в одной строке. Однако этот подход изначально будет отображать все элементы и не является решением, оптимизированным для производительности.

Не просто описывайте попытку решения; включите весь соответствующий код, чтобы мы могли воссоздать проблему и предложить решения.

mykaf 19.04.2024 03:55

@mykaf По сути, это ответ jla

Mohd. Abdul Sohail 20.04.2024 04:36
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы вычислить ширину каждого элемента, он должен быть отображен браузером. Поиск решения без предварительной визуализации звучит подозрительно как преждевременная оптимизация. Если в вашем меню нет тысяч элементов верхнего уровня, время, затрачиваемое на их рендеринг, будет незначительным; особенно по сравнению со временем, которое потребуется для запуска альтернативного сценария.

Как показывает следующий код, логика JavaScript довольно проста и не должна оказывать заметного влияния на производительность. Весь список элементов верхнего уровня необходимо повторить только один раз.

window.addEventListener( 'DOMContentLoaded', () => {
    const menu = document.querySelector( '#menu' )
    const items = menu.querySelectorAll( '.item' )
    const viewMore = menu.querySelector( '.view-more' )
    const overflow = menu.querySelector( '#overflow-menu' )
    
    const maxWidth = menu.offsetWidth
    let accumulator = viewMore.offsetWidth
    let c = 0
    
    while ( accumulator <= maxWidth && c < items.length - 1 ) {
        accumulator += items[c].offsetWidth
        c++
    }
    
    for ( c--; c < items.length; c++ ) {
        if ( ! items[c].classList.contains( 'view-more' ) ) {
            overflow.appendChild(items[c]);
        }
    }
    
    viewMore.addEventListener( 'click', () => {
        overflow.classList.toggle( 'visible' ) 
    } )
} )
#menu {
    display: flex;
}
.item {
    padding: 5px 10px;
    cursor: pointer;
    white-space: nowrap;
    color: black;
}
.item.view-more {
    background-color: black;
    color: white;
    border-radius: 5px;
    position: relative;
}
#overflow-menu {
    position: absolute;
    top: 100%;
    right: 0;
    display: none;
    flex-direction: column;
    background-color: white;
    box-shadow: 0 0 10px black;
}
#overflow-menu.visible {
    display: flex;
}
<div id = "menu">
  <div class = "item">Text</div>
  <div class = "item">Of Varying</div>
  <div class = "item">Lengths</div>
  <div class = "item">That The Browser</div>
  <div class = "item">Must</div>
  <div class = "item">Render</div>
  <div class = "item">In</div>
  <div class = "item">Order To</div>
  <div class = "item">Determine</div>
  <div class = "item">The</div>
  <div class = "item">Final Width</div>
  <div class = "item">:)</div>
  
  <div class = "item view-more">
      View More
      <div id = "overflow-menu"></div>
  </div>
</div>

Другие вопросы по теме