У меня простая динамическая панель навигации (количество элементов и текст можно изменить). Я хочу показать на экране первые X элементов, которые могут поместиться в одну строку, вместе с раскрывающимся списком «Показать больше», куда будут помещены все переполненные элементы, т. е. элементы, оставшиеся после размещения первых X элементов в строке.
Я попытался добиться этого, вычислив ширину каждого элемента (ширина текста + отступ кнопки), проверив ширину экрана, а затем поместив только первые X элементов, общая ширина которых (плюс ширина кнопки «показать больше») равна меньше ширины экрана. Теперь самое сложное — вычислить ширину текста. Если мы сначала визуализируем все элементы, то легко получить визуализированную ширину каждого элемента, а затем мы можем выполнить приведенное выше вычисление, чтобы проверить, какие элементы умещаются в одной строке. Однако этот подход изначально будет отображать все элементы и не является решением, оптимизированным для производительности.
@mykaf По сути, это ответ jla
Чтобы вычислить ширину каждого элемента, он должен быть отображен браузером. Поиск решения без предварительной визуализации звучит подозрительно как преждевременная оптимизация. Если в вашем меню нет тысяч элементов верхнего уровня, время, затрачиваемое на их рендеринг, будет незначительным; особенно по сравнению со временем, которое потребуется для запуска альтернативного сценария.
Как показывает следующий код, логика 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>
Не просто описывайте попытку решения; включите весь соответствующий код, чтобы мы могли воссоздать проблему и предложить решения.