Where can I find a jQuery accordian-type menu (or

2019-09-08 00:25发布

问题:

I would like to implement an accordian-style menu on my site. There are some requirements:

  • It must support multiple levels of depth (at least 3).
  • It must work like an accordian.
  • It must provide content about where the user is.

Additionally I would love if it supported ThemeRoller.

I was looking around and came across some menus that are very similar to what I'm looking for:

  • http://www.designchemical.com/lab/jquery-vertical-accordion-menu-plugin/examples/, however, it still shows all the other items in the parent menu after selecting an item. Also, has no ThemeRoller support.
  • http://www.filamentgroup.com/lab/jquery_ipod_style_and_flyout_menus/, stores history as a breadcrumb instead of menu items.
  • http://www.designchemical.com/lab/jquery-drill-down-menu-plugin/getting-started/, doesn't support jQuery 1.8.2 and displays the entire parent contaner's menu items after an item with children has been expanded. Also, has no ThemeRoller support.

What I'm really looking for is pretty much exactly what is over at the MSDN library. The MSDN menu is accordian-style and it hides everything not in the current level/container. It also keeps the parent item as a 'menu item' instead of as a breadcrumb.

If anyone has suggestions for such a menu I'd be happy to get them. Otherwise, I'd like to get the DesignChemical Drill-Down menu working with jQuery 1.8.2. The error I'm getting is rather ambiguous (from the demo page that comes with the menu):

Syntax error, unrecognized expression: [object Object][rel="7"]

The error is coming from the jQuery library itself, line 4679.

Any ideas how I can go about fixing this?

I've found that the problem only exists with jQuery v1.8.0 and later, it still works with v1.7.2.

回答1:

I know this is a bit of an old thread but taking on board what cjbarth has pointed out, i have done a few more tweeks to the code and it now works with the latest jquery 1.9.0 library.

Hope this helps somebody out :).

jquery.dcdrilldown.1.2.1 Source

    /*

     * DC jQuery Drill Down Menu - jQuery drill down ipod menu
     * Copyright (c) 2011 Design Chemical
     * 
     * Patched for jQuery version 1.9.0
     * By Tay - StackOverflow
     * Dual licensed under the MIT and GPL licenses:
     *  http://www.opensource.org/licenses/mit-license.php
     *  http://www.gnu.org/licenses/gpl.html
     *
     */

    (function($){

    //define the new for the plugin ans how to call it
    $.fn.dcDrilldown = function(options) {

    //set default options
    var defaults = {
        classWrapper    : 'dd-wrapper',
        classMenu       : 'dd-menu',
        classParent     : 'dd-parent',
        classParentLink : 'dd-parent-a',
        classActive     : 'active',
        classHeader     : 'dd-header',
        eventType       : 'click',
        hoverDelay      : 300,
        speed           : 'slow',
        saveState       : true,
        showCount       : true,
        classCount      : 'dd-count',
        classIcon       : 'dd-icon',
        linkType        : 'backlink',
        resetText       : 'All',
        headerTag       : 'h3',
        defaultText     : 'Select Option',
        includeHdr      : true
    };

    //call in the default options
    var options = $.extend(defaults, options);

    //act upon the element that is passed into the design
    return this.each(function(options){

        var $dcDrilldownObj = this;
        $($dcDrilldownObj).addClass(defaults.classMenu);
        var $wrapper = '<div class="'+defaults.classWrapper+'" />';
        $($dcDrilldownObj).wrap($wrapper);
        var $dcWrapper = $($dcDrilldownObj).parent();
        var objIndex = $($dcWrapper).index('.'+defaults.classWrapper);
        var idHeader = defaults.classHeader+'-'+objIndex;
        var idWrapper = defaults.classWrapper+'-'+objIndex;
        $($dcWrapper).attr('id',idWrapper);
        var $header = '<div id="'+idHeader+'" class="'+defaults.classHeader+'"></div>';

        setUpDrilldown();

        if(defaults.saveState == true){
            var cookieId = defaults.classWrapper+'-'+objIndex;
            checkCookie(cookieId, $dcDrilldownObj);
        }

        resetDrilldown($dcDrilldownObj, $dcWrapper);

        $('li a',$dcDrilldownObj).click(function(e){

            $link = this;
            $activeLi = $(this).parent('li').stop();
            $siblingsLi = $($activeLi).siblings();

            // Drilldown action
            if($('> ul',$activeLi).length){
                if($($link).hasClass(defaults.classActive)){
                    $('ul a',$activeLi).removeClass(defaults.classActive);
                    resetDrilldown($dcDrilldownObj, $dcWrapper);
                } else {
                    actionDrillDown($activeLi, $dcWrapper, $dcDrilldownObj);
                }
            }

            // Prevent browsing to link if has child links
            if($(this).next('ul').length > 0){
                e.preventDefault();
            }
        });

        // Set up accordion
        function setUpDrilldown(){

            $arrow = '<span class="'+defaults.classIcon+'"></span>';
            $($dcDrilldownObj).before($header);

            // Get width of menu container & height of list item
            var totalWidth = $($dcDrilldownObj).outerWidth();
            totalWidth += 'px';
            var itemHeight = $('li',$dcDrilldownObj).outerHeight(true);

            // Get height of largest sub menu
            var objUl = $('ul',$dcDrilldownObj);
            var maxItems = findMaxHeight(objUl);

            // Get level of largest sub menu
            var maxUl = objUl.parent().find('[rel=' + maxItems + ']');
            var getIndex = findMaxIndex(maxUl);

            // Set menu container height
            if(defaults.linkType == 'link'){
                menuHeight = itemHeight * (maxItems + getIndex);
            } else {
                menuHeight = itemHeight * maxItems;
            }
            $($dcDrilldownObj).css({height: menuHeight+'px', width: totalWidth});

            // Set sub menu width and offset
            $('li',$dcDrilldownObj).each(function(){
                $(this).css({width: totalWidth});
                $('ul',this).css({width: totalWidth, marginRight: '-'+totalWidth, marginTop: '0'});
                if($('> ul',this).length){
                    $(this).addClass(defaults.classParent);
                    $('> a',this).addClass(defaults.classParentLink).append($arrow);
                    if(defaults.showCount == true){
                        var parentLink = $('a:not(.'+defaults.classParentLink+')',this);
                        var countParent = parseInt($(parentLink).length);
                        getCount = countParent;
                        $('> a',this).append(' <span class="'+defaults.classCount+'">('+getCount+')</span>');
                    }
                }
            });

            // Add css class
            $('ul',$dcWrapper).each(function(){
                $('li:last',this).addClass('last');
            });
            $('> ul > li:last',$dcWrapper).addClass('last');
            if(defaults.linkType == 'link'){
                $(objUl).css('top',itemHeight+'px');
            }
        }

        // Breadcrumbs
        $('#'+idHeader).on('click', 'a', function(e){
            if($(this).hasClass('link-back')){
                linkIndex = $('#'+idWrapper+' .'+defaults.classParentLink+'.active').length;
                linkIndex = linkIndex-2;
                $('a.'+defaults.classActive+':last', $dcDrilldownObj).removeClass(defaults.classActive);
            } else {
                // Get link index
                var linkIndex = parseInt($(this).index('#'+idHeader+' a'));
                if(linkIndex == 0){
                    $('a',$dcDrilldownObj).removeClass(defaults.classActive);
                } else {
                    // Select equivalent active link
                    linkIndex = linkIndex-1;
                    $('a.'+defaults.classActive+':gt('+linkIndex+')',$dcDrilldownObj).removeClass(defaults.classActive);
                }
            }
            resetDrilldown($dcDrilldownObj, $dcWrapper);
            e.preventDefault();
        });
    });

    function findMaxHeight(element){
        var maxIndex = undefined;
        $(element).each(function(){
            var val = parseInt($('> li',this).length);
            $(this).attr('rel',val);
            if (maxIndex === undefined || maxIndex < val){
                maxIndex = val;
            }
        });
        if ($(element).find('li').length > maxIndex) {
        //the longest 'submenu' could be the root menu
            return 1
        } else {
            return maxIndex;
        }
    }

    function findMaxIndex(element){
        var maxIndex = undefined;
        $(element).each(function(){
            var val = parseInt($(this).parents('li').length);
            if (maxIndex === undefined || maxIndex < val) {
                maxIndex = val;
            }
        });
        return maxIndex;
    }

    // Retrieve cookie value and set active items
    function checkCookie(cookieId, obj){
        var cookieVal = $.cookie(cookieId);
        if(cookieVal != null){
            // create array from cookie string
            var activeArray = cookieVal.split(',');
            $.each(activeArray, function(index,value){
                var $cookieLi = $('li:eq('+value+')',obj);
                $('> a',$cookieLi).addClass(defaults.classActive);
            });
        }
    }

    // Drill Down
    function actionDrillDown(element, wrapper, obj){
        // Declare header
        var $header = $('.'+defaults.classHeader, wrapper);

        // Get new breadcrumb and header text
        var getNewBreadcrumb = $('h3',$header).html();
        var getNewHeaderText = $('> a',element).html();

        // Add new breadcrumb
        if(defaults.linkType == 'breadcrumb'){
            if(!$('ul',$header).length){
                $($header).prepend('<ul></ul>');
            }
            if(getNewBreadcrumb == defaults.defaultText){
                $('ul',$header).append('<li><a href="#" class="first">'+defaults.resetText+'</a></li>');
            } else {
                $('ul',$header).append('<li><a href="#">'+getNewBreadcrumb+'</a></li>');
            }
        }
        if(defaults.linkType == 'backlink'){
            if(!$('a',$header).length){
                $($header).prepend('<a href="#" class="link-back">'+getNewBreadcrumb+'</a>');
            } else {
                $('.link-back',$header).html(getNewBreadcrumb);
            }
        }
        if(defaults.linkType == 'link'){
            if(!$('a',$header).length){
                $($header).prepend('<ul><li><a href="#" class="first">'+defaults.resetText+'</a></li></ul>');
            }
        }
        // Update header text
        updateHeader($header, getNewHeaderText);

        // declare child link
        var activeLink = $('> a',element);

        // add active class to link
        $(activeLink).addClass(defaults.classActive);
        $('> ul li',element).show();
        $('> ul',element).animate({"margin-right": 0}, defaults.speed);

        // Find all sibling items & hide
        var $siblingsLi = $(element).siblings();
        $($siblingsLi).hide();

        // If using breadcrumbs hide this element
        if(defaults.linkType != 'link'){
            $(activeLink).hide();
        }

        // Write cookie if save state is on
        if(defaults.saveState == true){
            var cookieId = $(wrapper).attr('id');
            createCookie(cookieId, obj);
        }
    }

    // Drill Up
    function actionDrillUp(element, obj, wrapper){
        // Declare header
        var $header = $('.'+defaults.classHeader, wrapper);

        var activeLink = $('> a',element);
        var checklength = $('.'+defaults.classActive, wrapper).length;
        var activeIndex = $(activeLink).index('.'+defaults.classActive, wrapper);

        // Get width of menu for animating right
        var totalWidth = $(obj).outerWidth(true);
        $('ul',element).css('margin-right',-totalWidth+'px');

        // Show all elements
        $(activeLink).addClass(defaults.classActive);
        $('> ul li',element).show();
        $('a',element).show();

        // Get new header text from clicked link
        var getNewHeaderText = $('> a',element).html();
        $('h3',$header).html(getNewHeaderText);

        if(defaults.linkType == 'breadcrumb'){
            var breadcrumbIndex = activeIndex-1;
            $('a:gt('+activeIndex+')',$header).remove();
        }
    }

    function updateHeader(obj, html){
        if(defaults.includeHdr == true){
            if($('h3',obj).length){
                $('h3',obj).html(html);
            } else {
                $(obj).append('<'+defaults.headerTag+'>'+html+'</'+defaults.headerTag+'>');
            }
        }
    }

    // Reset accordion using active links
    function resetDrilldown(obj, wrapper){
        var $header = $('.'+defaults.classHeader, wrapper);
        $('ul',$header).remove();
        $('a',$header).remove();
        $('li',obj).show();
        $('a',obj).show();
        var totalWidth = $(obj).outerWidth(true);
        if(defaults.linkType == "link"){
            if($('a.'+defaults.classActive+':last',obj).parent('li').length){
                var lastActive = $('a.'+defaults.classActive+':last',obj).parent('li');
                $('ul',lastActive).css('margin-right',-totalWidth+'px');
            }else {
            $('ul',obj).css('margin-right',-totalWidth+'px');
            }
        } else {
            $('ul',obj).css('margin-right',-totalWidth+'px');
        }
        updateHeader($header, defaults.defaultText);

        // Write cookie if save state is on
        if(defaults.saveState == true){
            var cookieId = $(wrapper).attr('id');
            createCookie(cookieId, obj);
        }

        $('a.'+defaults.classActive,obj).each(function(i){
            var $activeLi = $(this).parent('li').stop();
            actionDrillDown($activeLi, wrapper, obj);
        });
    }

    // Write cookie
    function createCookie(cookieId, obj){
        var activeIndex = [];
        // Create array of active items index value
        $('a.'+defaults.classActive,obj).each(function(i){
            var $arrayItem = $(this).parent('li');
            var itemIndex = $('li',obj).index($arrayItem);
                activeIndex.push(itemIndex);
            });
        // Store in cookie
        $.cookie(cookieId, activeIndex, { path: '/' });
    }
};
})(jQuery);


回答2:

There is a bug in the jquery.dcdrilldown.1.2.js file (and the min version too). Simple go to line 103 and replace

var maxUl = $(objUl+'[rel="'+maxItems+'"]');

with

var maxUl = objUl.find('[rel='+maxItems+']');

and the menu will now work with jQuery v1.8.0 and later.

UPDATE:

I was doing more testing and found that if the root menu is the one with the greatest number of items, even the above fix won't help; a few other changes are still needed.

First, the above line needs to be:

var maxUl = objUl.parent().find('[rel=' + maxItems + ']');

Second, about line 184 the line

return maxIndex;

needs to be replaced with this code:

if ($(element).find('li').length > maxIndex) {
//the longest 'submenu' could be the root menu
    return 1
} else {
    return maxIndex;
}