1.jquery.multiSelect.js
if(jQuery) (function($){ // render the html for a single option function renderOption(id, option) { var html = '<label><input type="checkbox" name="' + id + '[]" value="' + option.value + '"'; if( option.selected ){ html += ' checked="checked"'; } html += ' />' + option.text + '</label>'; return html; } // render the html for the options/optgroups function renderOptions(id, options, o) { var html = ""; for(var i = 0; i < options.length; i++) { if(options[i].optgroup) { html += '<label class="optGroup">'; if(o.optGroupSelectable) { html += '<input type="checkbox" class="optGroup" />' + options[i].optgroup; } else { html += options[i].optgroup; } html += '</label><div class="optGroupContainer">'; html += renderOptions(id, options[i].options, o); html += '</div>'; } else { html += renderOption(id, options[i]); } } return html; } // Building the actual options function buildOptions(options) { var multiSelect = $(this); var multiSelectOptions = multiSelect.next('.multiSelectOptions'); var o = multiSelect.data("config"); var callback = multiSelect.data("callback"); // clear the existing options multiSelectOptions.html(""); var html = ""; // if we should have a select all option then add it if( o.selectAll ) { html += '<label class="selectAll"><input type="checkbox" class="selectAll" />' + o.selectAllText + '</label>'; } // generate the html for the new options html += renderOptions(multiSelect.attr('id'), options, o); multiSelectOptions.html(html); // variables needed to account for width changes due to a scrollbar var initialWidth = multiSelectOptions.width(); var hasScrollbar = false; // set the height of the dropdown options if(multiSelectOptions.height() > o.listHeight) { multiSelectOptions.css("height", o.listHeight + 'px'); hasScrollbar = true; } else { multiSelectOptions.css("height", ''); } // if the there is a scrollbar and the browser did not already handle adjusting the width (i.e. Firefox) then we will need to manaually add the scrollbar width var scrollbarWidth = hasScrollbar && (initialWidth == multiSelectOptions.width()) ? 17 : 0; // set the width of the dropdown options if((multiSelectOptions.width() + scrollbarWidth) < multiSelect.outerWidth()) { multiSelectOptions.css("width", multiSelect.outerWidth() - 2/*border*/ + 'px'); } else { multiSelectOptions.css("width", (multiSelectOptions.width() + scrollbarWidth) + 'px'); } // Apply bgiframe if available on IE6 if( $.fn.bgiframe ) multiSelect.next('.multiSelectOptions').bgiframe( { width: multiSelectOptions.width(), height: multiSelectOptions.height() }); // Handle selectAll oncheck if(o.selectAll) { multiSelectOptions.find('INPUT.selectAll').click( function() { // update all the child checkboxes multiSelectOptions.find('INPUT:checkbox').attr('checked', $(this).attr('checked')).parent("LABEL").toggleClass('checked', $(this).attr('checked')); }); } // Handle OptGroup oncheck if(o.optGroupSelectable) { multiSelectOptions.addClass('optGroupHasCheckboxes'); multiSelectOptions.find('INPUT.optGroup').click( function() { // update all the child checkboxes $(this).parent().next().find('INPUT:checkbox').attr('checked', $(this).attr('checked')).parent("LABEL").toggleClass('checked', $(this).attr('checked')); }); } // Handle all checkboxes multiSelectOptions.find('INPUT:checkbox').click( function() { // set the label checked class $(this).parent("LABEL").toggleClass('checked', $(this).attr('checked')); updateSelected.call(multiSelect); multiSelect.focus(); if($(this).parent().parent().hasClass('optGroupContainer')) { updateOptGroup.call(multiSelect, $(this).parent().parent().prev()); } if( callback ) { callback($(this)); } }); // Initial display multiSelectOptions.each( function() { $(this).find('INPUT:checked').parent().addClass('checked'); }); // Initialize selected and select all updateSelected.call(multiSelect); // Initialize optgroups if(o.optGroupSelectable) { multiSelectOptions.find('LABEL.optGroup').each( function() { updateOptGroup.call(multiSelect, $(this)); }); } // Handle hovers multiSelectOptions.find('LABEL:has(INPUT)').hover( function() { $(this).parent().find('LABEL').removeClass('hover'); $(this).addClass('hover'); }, function() { $(this).parent().find('LABEL').removeClass('hover'); }); // Keyboard multiSelect.keydown( function(e) { var multiSelectOptions = $(this).next('.multiSelectOptions'); // Is dropdown visible? if( multiSelectOptions.css('visibility') != 'hidden' ) { // Dropdown is visible // Tab if( e.keyCode == 9 ) { $(this).addClass('focus').trigger('click'); // esc, left, right - hide $(this).focus().next(':input').focus(); return true; } // ESC, Left, Right if( e.keyCode == 27 || e.keyCode == 37 || e.keyCode == 39 ) { // Hide dropdown $(this).addClass('focus').trigger('click'); } // Down || Up if( e.keyCode == 40 || e.keyCode == 38) { var allOptions = multiSelectOptions.find('LABEL'); var oldHoverIndex = allOptions.index(allOptions.filter('.hover')); var newHoverIndex = -1; // if there is no current highlighted item then highlight the first item if(oldHoverIndex < 0) { // Default to first item multiSelectOptions.find('LABEL:first').addClass('hover'); } // else if we are moving down and there is a next item then move else if(e.keyCode == 40 && oldHoverIndex < allOptions.length - 1) { newHoverIndex = oldHoverIndex + 1; } // else if we are moving up and there is a prev item then move else if(e.keyCode == 38 && oldHoverIndex > 0) { newHoverIndex = oldHoverIndex - 1; } if(newHoverIndex >= 0) { $(allOptions.get(oldHoverIndex)).removeClass('hover'); // remove the current highlight $(allOptions.get(newHoverIndex)).addClass('hover'); // add the new highlight // Adjust the viewport if necessary adjustViewPort(multiSelectOptions); } return false; } // Enter, Space if( e.keyCode == 13 || e.keyCode == 32 ) { var selectedCheckbox = multiSelectOptions.find('LABEL.hover INPUT:checkbox'); // Set the checkbox (and label class) selectedCheckbox.attr('checked', !selectedCheckbox.attr('checked')).parent("LABEL").toggleClass('checked', selectedCheckbox.attr('checked')); // if the checkbox was the select all then set all the checkboxes if(selectedCheckbox.hasClass("selectAll")) { multiSelectOptions.find('INPUT:checkbox').attr('checked', selectedCheckbox.attr('checked')).parent("LABEL").addClass('checked').toggleClass('checked', selectedCheckbox.attr('checked')); } updateSelected.call(multiSelect); if( callback ) callback($(this)); return false; } // Any other standard keyboard character (try and match the first character of an option) if( e.keyCode >= 33 && e.keyCode <= 126 ) { // find the next matching item after the current hovered item var match = multiSelectOptions.find('LABEL:startsWith(' + String.fromCharCode(e.keyCode) + ')'); var currentHoverIndex = match.index(match.filter('LABEL.hover')); // filter the set to any items after the current hovered item var afterHoverMatch = match.filter(function (index) { return index > currentHoverIndex; }); // if there were no item after the current hovered item then try using the full search results (filtered to the first one) match = (afterHoverMatch.length >= 1 ? afterHoverMatch : match).filter("LABEL:first"); if(match.length == 1) { // if we found a match then move the hover multiSelectOptions.find('LABEL.hover').removeClass('hover'); match.addClass('hover'); adjustViewPort(multiSelectOptions); } } } else { // Dropdown is not visible if( e.keyCode == 38 || e.keyCode == 40 || e.keyCode == 13 || e.keyCode == 32 ) { //up, down, enter, space - show // Show dropdown $(this).removeClass('focus').trigger('click'); multiSelectOptions.find('LABEL:first').addClass('hover'); return false; } // Tab key if( e.keyCode == 9 ) { // Shift focus to next INPUT element on page multiSelectOptions.next(':input').focus(); return true; } } // Prevent enter key from submitting form if( e.keyCode == 13 ) return false; }); } // Adjust the viewport if necessary function adjustViewPort(multiSelectOptions) { // check for and move down var selectionBottom = multiSelectOptions.find('LABEL.hover').position().top + multiSelectOptions.find('LABEL.hover').outerHeight(); if(selectionBottom > multiSelectOptions.innerHeight()){ multiSelectOptions.scrollTop(multiSelectOptions.scrollTop() + selectionBottom - multiSelectOptions.innerHeight()); } // check for and move up if(multiSelectOptions.find('LABEL.hover').position().top < 0){ multiSelectOptions.scrollTop(multiSelectOptions.scrollTop() + multiSelectOptions.find('LABEL.hover').position().top); } } // Update the optgroup checked status function updateOptGroup(optGroup) { var multiSelect = $(this); var o = multiSelect.data("config"); // Determine if the optgroup should be checked if(o.optGroupSelectable) { var optGroupSelected = true; $(optGroup).next().find('INPUT:checkbox').each( function() { if( !$(this).attr('checked') ) { optGroupSelected = false; return false; } }); $(optGroup).find('INPUT.optGroup').attr('checked', optGroupSelected).parent("LABEL").toggleClass('checked', optGroupSelected); } } // Update the textbox with the total number of selected items, and determine select all function updateSelected() { var multiSelect = $(this); var multiSelectOptions = multiSelect.next('.multiSelectOptions'); var o = multiSelect.data("config"); var i = 0; var selectAll = true; var display = ''; multiSelectOptions.find('INPUT:checkbox').not('.selectAll, .optGroup').each( function() { if( $(this).attr('checked') ) { i++; display = display + $(this).parent().text() + ', '; } else selectAll = false; }); // trim any end comma and surounding whitespace display = display.replace(//s*/,/s*$/,''); if( i == 0 ) { multiSelect.find("span").html( o.noneSelected ); } else { if( o.oneOrMoreSelected == '*' ) { multiSelect.find("span").html( display ); multiSelect.attr( "title", display ); } else { multiSelect.find("span").html( o.oneOrMoreSelected.replace('%', i) ); } } // Determine if Select All should be checked if(o.selectAll) { multiSelectOptions.find('INPUT.selectAll').attr('checked', selectAll).parent("LABEL").toggleClass('checked', selectAll); } } $.extend($.fn, { multiSelect: function(o, callback) { // Default options if( !o ) o = {}; if( o.selectAll == undefined ) o.selectAll = true; if( o.selectAllText == undefined ) o.selectAllText = "选择全部"; if( o.noneSelected == undefined ) o.noneSelected = '--请选择--'; if( o.oneOrMoreSelected == undefined ) o.oneOrMoreSelected = '% selected'; if( o.optGroupSelectable == undefined ) o.optGroupSelectable = false; if( o.listHeight == undefined ) o.listHeight = 150; // Initialize each multiSelect $(this).each( function() { var select = $(this); var html = '<a href="javascript:;" mce_href="javascript:;" class="multiSelect"><span></span></a>'; html += '<div class="multiSelectOptions" style="position: absolute; z-index: 99999; visibility: hidden;" mce_style="position: absolute; z-index: 99999; visibility: hidden;"></div>'; $(select).after(html); var multiSelect = $(select).next('.multiSelect'); var multiSelectOptions = multiSelect.next('.multiSelectOptions'); // if the select object had a width defined then match the new multilsect to it multiSelect.find("span").css("width", $(select).width() + 'px'); // Attach the config options to the multiselect multiSelect.data("config", o); // Attach the callback to the multiselect multiSelect.data("callback", callback); // Serialize the select options into json options var options = []; $(select).children().each( function() { if(this.tagName.toUpperCase() == 'OPTGROUP') { var suboptions = []; options.push({ optgroup: $(this).attr('label'), options: suboptions }); $(this).children('OPTION').each( function() { if( $(this).val() != '' ) { suboptions.push({ text: $(this).html(), value: $(this).val(), selected: $(this).attr('selected') }); } }); } else if(this.tagName.toUpperCase() == 'OPTION') { if( $(this).val() != '' ) { options.push({ text: $(this).html(), value: $(this).val(), selected: $(this).attr('selected') }); } } }); // Eliminate the original form element $(select).remove(); // Add the id that was on the original select element to the new input multiSelect.attr("id", $(select).attr("id")); // Build the dropdown options buildOptions.call(multiSelect, options); // Events multiSelect.hover( function() { $(this).addClass('hover'); }, function() { $(this).removeClass('hover'); }).click( function() { // Show/hide on click if( $(this).hasClass('active') ) { $(this).multiSelectOptionsHide(); } else { $(this).multiSelectOptionsShow(); } return false; }).focus( function() { // So it can be styled with CSS $(this).addClass('focus'); }).blur( function() { // So it can be styled with CSS $(this).removeClass('focus'); }); // Add an event listener to the window to close the multiselect if the user clicks off $(document).click( function(event) { // If somewhere outside of the multiselect was clicked then hide the multiselect if(!($(event.target).parents().andSelf().is('.multiSelectOptions'))){ multiSelect.multiSelectOptionsHide(); } }); }); }, // Update the dropdown options multiSelectOptionsUpdate: function(options) { buildOptions.call($(this), options); }, // Hide the dropdown multiSelectOptionsHide: function() { $(this).removeClass('active').removeClass('hover').next('.multiSelectOptions').css('visibility', 'hidden'); }, // Show the dropdown multiSelectOptionsShow: function() { var multiSelect = $(this); var multiSelectOptions = multiSelect.next('.multiSelectOptions'); var o = multiSelect.data("config"); // Hide any open option boxes $('.multiSelect').multiSelectOptionsHide(); multiSelectOptions.find('LABEL').removeClass('hover'); multiSelect.addClass('active').next('.multiSelectOptions').css('visibility', 'visible'); multiSelect.focus(); // reset the scroll to the top multiSelect.next('.multiSelectOptions').scrollTop(0); // Position it var offset = multiSelect.position(); multiSelect.next('.multiSelectOptions').css({ top: offset.top + $(this).outerHeight() + 'px' }); multiSelect.next('.multiSelectOptions').css({ left: offset.left + 'px' }); }, // get a coma-delimited list of selected values selectedValuesString: function() { var selectedValues = ""; $(this).next('.multiSelectOptions').find('INPUT:checkbox:checked').not('.optGroup, .selectAll').each(function() { selectedValues += $(this).attr('value') + ","; }); // trim any end comma and surounding whitespace return selectedValues.replace(//s*/,/s*$/,''); } }); // add a new ":startsWith" search filter $.expr[":"].startsWith = function(el, i, m) { var search = m[3]; if (!search) return false; return eval("/^[/s]*" + search + "/i").test($(el).text()); }; })(jQuery);
2.jquery.multiSelect.css
a.multiSelect { background: #FFF url(dropdown.blue.png) right center no-repeat; border: solid 1px #BBB; padding-right: 20px; position: relative; cursor: default; text-decoration: none; color: black; display: -moz-inline-stack; display: inline-block; vertical-align: top; } a.multiSelect:link, a.multiSelect:visited, a.multiSelect:hover, a.multiSelect:active { color: black; text-decoration: none; } a.multiSelect span { margin: 1px 0px 1px 3px; overflow: hidden; display: -moz-inline-stack; display: inline-block; white-space: nowrap; } a.multiSelect.hover { background-image: url(dropdown.blue.hover.png); } a.multiSelect.active, a.multiSelect.focus { border: inset 1px #000; } a.multiSelect.active { background-image: url(dropdown.blue.active.png); } .multiSelectOptions { margin-top: -1px; overflow-y: auto; overflow-x: hidden; border: solid 1px #B2B2B2; background: #FFF; } .multiSelectOptions LABEL { padding: 0px 2px; display: block; white-space: nowrap; } .multiSelectOptions LABEL.optGroup { font-weight: bold; } .multiSelectOptions .optGroupContainer LABEL { padding-left: 10px; } .multiSelectOptions.optGroupHasCheckboxes .optGroupContainer LABEL { padding-left: 18px; } .multiSelectOptions input{ vertical-align: middle; } .multiSelectOptions LABEL.checked { background-color: #dce5f8; } .multiSelectOptions LABEL.selectAll { border-bottom: dotted 1px #CCC; } .multiSelectOptions LABEL.hover { background-color: #3399ff; color: white; }
3.应用:
在使用该插件时需要先包含jquery.js文件
使用时定义一个下拉列表,它应该包含multiple="multiple"属性,然后如下定义:
$(document).ready(function(){ $("select").multiSelect({oneOrMoreSelected:'*'}); }
若想获得多选框内的值可以如下:
$('select').text();
也可以获得列表内由所选option的value值组成的字符串,用‘,’隔开,如下:
$('select').selectedValuesString();
其它方法也可仿照上面的方式调用