我有一个包含 12 个项目的导航,当分辨率变小时,项目会放在新行中。我需要做到当一个项目不再适合导航时,它应该在导航的右侧放置一个“更多”下拉按钮。并将不适合下拉列表的项目放入其中。 如果你不明白我的意思,请看下面的图片。
但问题是导航项并不总是相同的宽度,因为导航项是从 REST api 生成的。
我尝试制作 jQuery 脚本来计算项目宽度并将其添加到导航中。 这是我创建的脚本,我做得很匆忙,所以非常糟糕。
我需要帮助如何正确计算项目的宽度和导航宽度,以及计算何时将项目添加到导航或从导航中删除项目。
如果您看不到,这是图片:http://img.hr/aagV
/*
* Here we check how many items can we put on the navigation bar
* If item doesn't fit we clone it on the more dropdown button
*/
function removeMany() {
var i = $items.length - 1;
if (itemsWidth > navWidth) {
while (itemsWidth > navWidth) {
$($items[i]).removeClass('first-level-item').addClass('second-level-item');
dropdownItems.push($items[i]);
$($items[i]).removeClass('showed');
$items.pop();
i--;
getItemsWidth();
}
$nav.append($navMore);
dropdownItems.reverse().forEach(function (element, index, array) {
$('ul.second-level').append(element);
});
getItems();
}
}
//If window is resized to bigger resolution we need to put back items on the navbar
function addMany() {
var i = dropdownItems.length - 1;
if (dropdownItems.length != 0) {
do {
$('ul.first-level').append(dropdownItems.reverse()[i]);
$items.push(dropdownItems[i]);
dropdownItems.pop();
i--;
getItemsWidth();
} while (itemsWidth < navWidth);
$navMore.remove();
$items.each(function (i) {
$(this).addClass('first-level-item showed').removeClass('second-level-item');
});
if (!(dropdownItems != 0)) {
return;
} else {
$nav.append($navMore);
}
}
}
body {
margin: 0;
padding: 0;
border: 0; }
ul, li {
margin: 0;
padding: 0;
list-style: none; }
ul.second-level li {
display: block !important; }
ul.second-level li > a {
color: black; }
a {
color: #fff;
text-decoration: none;
text-transform: uppercase; }
.second-level-item a {
color: #333 !important; }
.navigation {
width: 960px;
max-width: 100%;
background: #211;
color: #aaa;
margin: 0 auto; }
.first-level .first-level-item {
display: inline-block;
padding: 10px; }
.first-level .item-more {
display: inline-block; }
.first-level .item-more .second-level-item {
display: inline-block; }
.second-level {
position: absolute;
top: 100%;
right: 0;
width: 200px;
background: #fff;
padding: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4); }
.has-second-level {
position: relative; }
.has-second-level .second-level {
display: none; }
.has-second-level:hover {
background: #fff;
color: #000; }
.has-second-level:hover .second-level {
display: block; }
/*# sourceMappingURL=style.css.map */
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DropDown</title>
<link rel="stylesheet" href="css/reset.css"/>
<link rel="stylesheet" href="css/style.css"/>
</head>
<body>
<nav class="navigation">
<ul class="first-level">
<li class="first-level-item showed"><a href="#">Introduction to Irish Culture</a></li>
<li class="first-level-item showed"><a href="#">Cellular and Molecular Neurobiology</a></li>
<li class="first-level-item showed"><a href="#">Guitar foundations</a></li>
<li class="first-level-item showed"><a href="#">Startup Inovation</a></li>
<li class="first-level-item showed"><a href="#">Astrophysics</a></li>
<li class="first-level-item item-more has-second-level">
<span> More </span>
<ul class="second-level">
</ul>
</li>
</ul>
</nav>
<script src="https://code.jquery.com/jquery-2.1.1.js"></script>
</body>
</html>
如果您有固定宽度的列表项,那么收集额外的列表项并将它们推送到单独的列表中很简单。这是一个简单的例子。解释在代码注释中。
全屏查看代码片段并尝试更改窗口宽度。
也是小提琴:http://jsfiddle.net/abhitalks/860LzgLL/
全屏:http://jsfiddle.net/abhitalks/860LzgLL/embedded/result/
片段:
var elemWidth, fitCount, fixedWidth = 120,
$menu = $("ul#menu"), $collectedSet;
// Assuming that the list-items are of fixed-width.
collect();
$(window).resize(collect);
function collect() {
// Get the container width
elemWidth = $menu.width();
// Calculate how many list-items can be accomodated in that width
fitCount = Math.floor(elemWidth / fixedWidth) - 1;
// Create a new set of list-items more than the fit count
$collectedSet = $menu.children(":gt(" + fitCount + ")");
// Empty the collection submenu and add the cloned collection set
$("#submenu").empty().append($collectedSet.clone());
}
* { box-sizing: border-box; margin: 0; padding: 0; }
div { position: relative; background-color: #ccc; height: 32px; overflow: visible; }
ul#menu, ol { height: 32px; max-width: 80%; overflow: hidden; }
ul#menu > li, ol > li { display: block; float: left; height: 32px; width: 120px; padding: 4px 8px; }
ol { position: absolute; right: 0; top: 0; overflow: visible; }
ol > li { min-width: 120px; }
ol ul { position: absolute; top: 120%; right: 10%; }
ol li ul > li { list-style: none; background-color: #eee; border: 1px solid gray; padding: 4px 8px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul id="menu">
<li>Option One</li><li>Option Two</li><li>Option Three</li>
<li>Option Four</li><li>Option Five</li><li>Option Six</li>
</ul>
<ol><li>Collected<ul id="submenu"></ul></li></ol>
</div>
这与您对列表项的不同/可变宽度的查询有关。会有微小的改变。
也是小提琴:http://jsfiddle.net/abhitalks/tkbmcupt/1/
全屏:http://jsfiddle.net/abhitalks/tkbmcupt/1/embedded/result/
片段:
var elemWidth, fitCount, varWidth = 0, ctr, $menu = $("ul#menu"), $collectedSet;
// Get static values here first
ctr = $menu.children().length; // number of children will not change
$menu.children().each(function() {
varWidth += $(this).outerWidth(); // widths will not change, so just a total
});
collect(); // fire first collection on page load
$(window).resize(collect); // fire collection on window resize
function collect() {
elemWidth = $menu.width(); // width of menu
// Calculate fitCount on the total width this time
fitCount = Math.floor((elemWidth / varWidth) * ctr) - 1;
// Reset display and width on all list-items
$menu.children().css({"display": "block", "width": "auto"});
// Make a set of collected list-items based on fitCount
$collectedSet = $menu.children(":gt(" + fitCount + ")");
// Empty the more menu and add the collected items
$("#submenu").empty().append($collectedSet.clone());
// Set display to none and width to 0 on collection,
// because they are not visible anyway.
$collectedSet.css({"display": "none", "width": "0"});
}
* { box-sizing: border-box; margin: 0; padding: 0; }
div { position: relative; background-color: #ccc; height: 32px; overflow: visible; }
ul#menu, ol { height: 32px; max-width: 80%; overflow: hidden; }
ul#menu > li, ol > li { display: block; float: left; height: 32px; white-space: nowrap; padding: 4px 8px; }
ol { position: absolute; right: 0; top: 0; overflow: visible; }
ol > li { min-width: 120px; }
ol ul { position: absolute; top: 120%; right: 10%; }
ol li ul > li { list-style: none; background-color: #eee; border: 1px solid gray; padding: 4px 8px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul id="menu">
<li>Option One</li><li>Option Two</li><li>Option Three</li>
<li>Option Four</li><li>Option Five</li><li>Option Six</li>
</ul>
<ol><li>Collected<ul id="submenu"></ul></li></ol>
</div>
可以并且应该进行优化(因为从我的测试来看,它的效率相当低),但这取决于你。
$(document).ready(function(){
var moreW = $(".more").outerWidth(), //width of your "more" element
totalW = -moreW, //cumulated width of list elements
totalN = $('.nav li').length - 1, //number of elements minus the "more" element
dw = document.documentElement.clientWidth;
$('.nav li').each(function(){
totalW += $(this).outerWidth();
});
function moveToDropdown(){
dw = document.documentElement.clientWidth;
//moves elements into the list
while(totalW > (dw - moreW)){
var temp = $(".nav li:nth-last-child(2)"); //element to be moved
totalW = totalW - temp.outerWidth();
$(".dropdown").append(temp.clone());
temp.remove();
}
//moves elements out of the list
var newList = $('.dropdown li').length; //check if we have elements
if(newList > 0){
var element = $('.dropdown li:last-child'), //element to be moved
elementW = $('.dropdown li:last-child').outerWidth(); //width of element to be moved
if(totalW + elementW < dw - moreW){
while(totalW + elementW < dw - moreW ){
var element = $('.dropdown li:last-child'),
elementW = $('.dropdown li:last-child').outerWidth();
totalW = totalW + elementW;
$(".nav > li:last-child").before(element.clone());
element.remove();
}
}
}
}
moveToDropdown();
$(window).resize(moveToDropdown)
});
.clearfix:after{
display:block;
content:'';
clear:both;
}
body,html{
width:100%;
height:100%;
margin:0;
padding:0;
}
ul{
list-style:none;
width:100%;
padding:0;
margin:0;
}
ul li{
float:left;
padding:5px;
}
.nav > li {
position:relative;
}
.nav ul{
position:absolute;
top:25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="nav clearfix">
<li><a href="#">Item</a></li>
<li><a href="#">Item</a></li>
<li><a href="#">Item</a></li>
<li><a href="#">Item</a></li>
<li><a href="#">Item</a></li>
<li><a href="#">Item</a></li>
<li><a href="#">Item</a></li>
<li class="more">
<a href="#">more</a>
<ul class="dropdown">
<!-- we'll add elements here -->
</ul>
</li>
</ul>
这个问题太老了,但我也想发布我的答案。也许这是更干净、更简单的方法。我创建了一支笔:https://codepen.io/sergi95/pen/bmNoML
<div id="mainMenu" class="main-menu">
<ul id="autoNav" class="main-nav">
<li>
<a href="#">home</a>
</li>
<li>
<a href="#">about us</a>
</li>
<li>
<a href="#">portfolio</a>
</li>
<li>
<a href="#">team</a>
</li>
<li>
<a href="#">blog</a>
</li>
<li>
<a href="#">contact</a>
</li>
<li id="autoNavMore" class="auto-nav-more">
<a href="#" class="more-btn">more</a>
<ul id="autoNavMoreList" class="auto-nav-more-list">
<li>
<a href="#">policy</a>
</li>
</ul>
</li>
</ul>
const $mainMenu = $("#mainMenu");
const $autoNav = $("#autoNav");
const $autoNavMore = $("#autoNavMore");
const $autoNavMoreList = $("#autoNavMoreList");
autoNavMore = () => {
let childNumber = 2;
if($(window).width() >= 320) {
// GET MENU AND NAV WIDTH
const $menuWidth = $mainMenu.width();
const $autoNavWidth = $autoNav.width();
if($autoNavWidth > $menuWidth) {
// CODE FIRES WHEN WINDOW SIZE GOES DOWN
$autoNav.children(`li:nth-last-child(${childNumber})`).prependTo($autoNavMoreList);
autoNavMore();
} else {
// CODE FIRES WHEN WINDOW SIZE GOES UP
const $autoNavMoreFirst = $autoNavMoreList.children('li:first-child').width();
// CHECK IF ITEM HAS ENOUGH SPACE TO PLACE IN MENU
if(($autoNavWidth + $autoNavMoreFirst) < $menuWidth) {
$autoNavMoreList.children('li:first-child').insertBefore($autoNavMore);
}
}
if($autoNavMoreList.children().length > 0) {
$autoNavMore.show();
childNumber = 2;
} else {
$autoNavMore.hide();
childNumber = 1;
}
}
}
// INIT
autoNavMore();
$(window).resize(autoNavMore);
.main-menu {
max-width: 800px;
}
.main-nav {
display: inline-flex;
padding: 0;
list-style: none;
}
.main-nav li a {
padding: 10px;
text-transform: capitalize;
white-space: nowrap;
font-size: 30px;
font-family: sans-serif;
text-decoration: none;
}
.more-btn {
color: red;
}
.auto-nav-more {
position: relative;
}
.auto-nav-more-list {
position: absolute;
right: 0;
opacity: 0;
visibility: hidden;
transition: 0.2s;
text-align: right;
padding: 0;
list-style: none;
background: grey;
border-radius: 4px;
}
.auto-nav-more:hover .auto-nav-more-list {
opacity: 1;
visibility: visible;
}
Abhitalks 制作的脚本对于不同的元素大小无法正常工作。我稍微修改了代码,它确实做到了:
$(function() {
function makeMenuFit() {
//Get data
var menuSize = menu.width();
//Determine how many items that fit
var menuTotalWidth = 0;
var itemThatFit = 0;
for(var i = 0; i < menuItems.length; i++) {
menuTotalWidth += menuItems[i];
if(menuTotalWidth <= menuSize) {
itemThatFit++;
continue;
}
break;
}
menu.children().css({"display": "block", "width": "auto"});
var collectedSet = menu.children(":gt(" + (itemThatFit - 1) + ")");
$("#submenu").empty().append(collectedSet.clone());
collectedSet.css({"display": "none", "width": "0"});
}
var menu = $(".tabletNavigation > ul");
var menuItems = [];
menu.children().each(function() {
menuItems.push($(this).outerWidth());
});
$(window).resize(makeMenuFit);
makeMenuFit();
});
@Sergo Kupreishvili 的解决方案非常出色。我只是稍微改进了一下。仅当菜单无法适合调整大小的窗口时,才会出现“更多”按钮。 检查代码笔:https://codepen.io/adnanahmed237/pen/vYorqdr
$(function () {
const $mainMenu = $("#mainMenu");
const $autoNav = $("#autoNav");
const $autoNavMore = $("#autoNavMore");
const $autoNavMoreList = $("#autoNavMoreList");
let originalItems = []; // Store original items
// Store original items on load
$autoNav.children("li:not(#autoNavMore)").each(function () {
originalItems.push($(this));
});
function autoNavMore() {
const menuWidth = $mainMenu.width();
let usedWidth = 0;
$autoNavMoreList.empty(); // Clear "More" dropdown
// Reset menu to original items on each resize
$autoNav.prepend(originalItems);
// Iterate over menu items to check if they fit
$autoNav.children("li:not(#autoNavMore)").each(function () {
usedWidth += $(this).outerWidth(true);
if (usedWidth > menuWidth) {
$(this).appendTo($autoNavMoreList); // Move excess items to "More" dropdown
}
});
// Toggle "More" button based on list content
$autoNavMore.toggle($autoNavMoreList.children().length > 0);
}
// Initialize and set event listener for window resize
autoNavMore();
$(window).resize(autoNavMore);
});
.main-menu {
max-width: 1280px;
margin: 0 auto;
}
.main-nav {
display: inline-flex;
padding: 0;
list-style: none;
}
.main-nav li a {
padding: 10px;
text-transform: capitalize;
white-space: nowrap;
font-size: 20px;
font-family: sans-serif;
text-decoration: none;
}
.more-btn {
color: red;
}
.auto-nav-more {
position: relative;
display: none;
}
.auto-nav-more-list {
position: absolute;
right: 0;
opacity: 0;
visibility: hidden;
transition: 0.2s;
text-align: right;
padding: 0;
list-style: none;
background: grey;
border-radius: 4px;
}
.auto-nav-more:hover .auto-nav-more-list {
opacity: 1;
visibility: visible;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<!-- MAIN MENU -->
<div id="mainMenu" class="main-menu">
<ul id="autoNav" class="main-nav">
<li><a href="#">home</a></li>
<li><a href="#">about us</a></li>
<li><a href="#">portfolio</a></li>
<li><a href="#">team</a></li>
<li><a href="#">blog</a></li>
<li><a href="#">contact</a></li>
<li><a href="#">Page 1</a></li>
<li><a href="#">Page 2</a></li>
<li><a href="#">Page 3</a></li>
<li><a href="#">Page 4</a></li>
<li><a href="#">Page 5</a></li>
<li id="autoNavMore" class="auto-nav-more">
<a href="#" class="more-btn">more</a>
<ul id="autoNavMoreList" class="auto-nav-more-list"></ul>
</li>
</ul>
</div>
<!-- MAIN MENU END -->
<p>Resize the window to test the menu.</p>