我有一个简单的动态导航栏(项目数量和文本可以更改)。我想显示屏幕上可以容纳在一行中的前 X 个项目以及“显示更多”下拉列表,所有溢出的项目都将进入其中,即在将前 X 个项目容纳在一行中后留下的项目。
我尝试通过计算每个项目的宽度(文本宽度+按钮填充)、检查屏幕宽度,然后仅放置组合宽度(加上“显示更多”按钮的宽度)的前 X 个项目来实现此目的小于屏幕宽度。现在具有挑战性的部分是计算文本宽度。如果我们首先渲染所有元素,那么很容易获得每个项目的渲染宽度,然后我们可以进行上述计算来检查哪些元素适合单行。然而,这种方法最初会渲染所有元素,并不是性能优化的解决方案。
要计算每个项目的宽度,它必须由浏览器渲染。找到一个不首先渲染的解决方案听起来很像“过早优化”。除非菜单中有数千个顶级项目,否则渲染它们所花费的时间可以忽略不计;特别是与运行替代脚本解决方案所需的时间相比。 如下面的代码所示,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 overflowItems = []
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>