adding more button for list in responsive navigation

前端 未结 4 1088
北恋
北恋 2021-01-03 13:52

I have a navigation of lets say 12 items, and when resolution gets smaller items drop in a new line. I need to make that when an item doesn\'t fit on a navigation anymore it

相关标签:
4条回答
  • 2021-01-03 14:03

    If you have fixed-width list-items, then it is simple to collect extra list-items and push them into a separate list. Here is a simple example. Explanation is in the code comments.

    View the snippet in full-screen and try changing the window width.

    Also a Fiddle: http://jsfiddle.net/abhitalks/860LzgLL/

    Full Screen: http://jsfiddle.net/abhitalks/860LzgLL/embedded/result/

    Snippet:

    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>


    Update:

    This is regarding your query on differing / variable widths of list-items. There would be a minor change.

    Also a Fiddle: http://jsfiddle.net/abhitalks/tkbmcupt/1/

    Full Screen: http://jsfiddle.net/abhitalks/tkbmcupt/1/embedded/result/

    Snippet:

    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>

    0 讨论(0)
  • 2021-01-03 14:08

    This question is too old, but i want to post my answer too. Maybe this is more cleaner and easier way. I have created a pen: 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;
        }
    
    0 讨论(0)
  • 2021-01-03 14:14

    Can and SHOULD be optimised (as it is quite inefficient from what i've tested), but that's up to you.

    $(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>

    0 讨论(0)
  • 2021-01-03 14:17

    The script that Abhitalks made did not work properly for different element sizes. I modified the code a little bit do that it does:

    $(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();
    });
    
    0 讨论(0)
提交回复
热议问题