jquery Select 实现搜索以及checkbox多选

演示: 点击打开链接

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        body {
            font-family: 'Open Sans';
        }

        .container {
            margin: 10px auto;
            max-width: 640px;
        }

        .fs-wrap {
            position: relative;
            display: inline-block;
            width: 200px;
            font-size: 12px;
            line-height: 1;
        }

        .fs-label-wrap {
            position: relative;
            border: 1px solid #ccc;
            cursor: default;
        }

        .fs-label-wrap,
        .fs-dropdown {
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
        }

        .fs-label-wrap .fs-label {
            padding: 4px 22px 4px 8px;
            text-overflow: ellipsis;
            white-space: nowrap;
            overflow: hidden;
        }

        .fs-arrow {
            width: 0;
            height: 0;
            border-left: 6px solid transparent;
            border-right: 6px solid transparent;
            border-top: 6px solid #000;
            position: absolute;
            top: 0;
            right: 5px;
            bottom: 0;
            margin: auto;
        }

        .fs-dropdown {
            position: absolute;
            background-color: #fff;
            border: 1px solid #ccc;
            margin-top: 5px;
            width: 100%;
            z-index: 1000;
        }

        .fs-dropdown .fs-options {
            max-height: 200px;
            overflow: auto;
        }

        .fs-search input {
            width: 100%;
            padding: 2px 4px;
            border: 0;
        }

        .fs-option,
        .fs-search,
        .fs-optgroup-label {
            padding: 6px 8px;
            border-bottom: 1px solid #eee;
            cursor: default;
        }

        .fs-option {
            cursor: pointer;
        }

        .fs-option.hl {
            background-color: #f5f5f5;
        }

        .fs-wrap.multiple .fs-option {
            position: relative;
            padding-left: 30px;
        }

        .fs-wrap.multiple .fs-checkbox {
            position: absolute;
            display: block;
            width: 30px;
            top: 0;
            left: 0;
            bottom: 0;
        }

        .fs-wrap.multiple .fs-option .fs-checkbox i {
            position: absolute;
            margin: auto;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
            width: 14px;
            height: 14px;
            border: 1px solid #aeaeae;
            border-radius: 2px;
            background-color: #fff;
        }

        .fs-wrap.multiple .fs-option.selected .fs-checkbox i {
            background-color: rgb(17, 169, 17);
            border-color: transparent;
            background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAGCAYAAAD+Bd/7AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNXG14zYAAABMSURBVAiZfc0xDkAAFIPhd2Kr1WRjcAExuIgzGUTIZ/AkImjSofnbNBAfHvzAHjOKNzhiQ42IDFXCDivaaxAJd0xYshT3QqBxqnxeHvhunpu23xnmAAAAAElFTkSuQmCC');
            background-repeat: no-repeat;
            background-position: center;
        }

        .fs-wrap .fs-option:hover {
            background-color: #f5f5f5;
        }

        .fs-optgroup-label {
            font-weight: bold;
        }

        .hidden {
            display: none;
        }
    </style>
</head>

<body>
<div id="main_demo">
    <div class="container">
        <select class="demo" multiple="multiple">
            <optgroup label="Languages">
                <option value="cp">C++</option>
                <option value="cs">C#</option>
                <option value="oc">Object C</option>
                <option value="c">C</option>
            </optgroup>
            <optgroup label="Scripts">
                <option value="js">JavaScript</option>
                <option value="php">PHP</option>
                <option value="asp">ASP</option>
                <option value="jsp">JSP</option>
            </optgroup>
        </select>
    </div>
    <script src="jquery-3.2.1.min.js"></script>
    <script>
        $(function () {
            $('.demo').fSelect();
        });

        (function ($) {

            $.fn.fSelect = function (options) {

                if (typeof options == 'string') {
                    var settings = options;
                }
                else {
                    var settings = $.extend({
                        placeholder: 'Select some options',
                        numDisplayed: 3,
                        overflowText: '{n} selected',
                        searchText: 'Search',
                        showSearch: true
                    }, options);
                }


                /**
                 * Constructor
                 */
                function fSelect(select, settings) {
                    this.$select = $(select);
                    this.settings = settings;
                    this.create();
                }


                /**
                 * Prototype class
                 */
                fSelect.prototype = {
                    create: function () {
                        var multiple = this.$select.is('[multiple]') ? ' multiple' : '';
                        this.$select.wrap('<div class="fs-wrap' + multiple + '"></div>');
                        this.$select.before('<div class="fs-label-wrap"><div class="fs-label">' + this.settings.placeholder + '</div><span class="fs-arrow"></span></div>');
                        this.$select.before('<div class="fs-dropdown hidden"><div class="fs-options"></div></div>');
                        this.$select.addClass('hidden');
                        this.$wrap = this.$select.closest('.fs-wrap');
                        this.reload();
                    },

                    reload: function () {
                        if (this.settings.showSearch) {
                            var search = '<div class="fs-search"><input type="search" placeholder="' + this.settings.searchText + '" /></div>';
                            this.$wrap.find('.fs-dropdown').prepend(search);
                        }
                        var choices = this.buildOptions(this.$select);
                        this.$wrap.find('.fs-options').html(choices);
                        this.reloadDropdownLabel();
                    },

                    destroy: function () {
                        this.$wrap.find('.fs-label-wrap').remove();
                        this.$wrap.find('.fs-dropdown').remove();
                        this.$select.unwrap().removeClass('hidden');
                    },

                    buildOptions: function ($element) {
                        var $this = this;

                        var choices = '';
                        $element.children().each(function (i, el) {
                            var $el = $(el);

                            if ('optgroup' == $el.prop('nodeName').toLowerCase()) {
                                choices += '<div class="fs-optgroup">';
                                choices += '<div class="fs-optgroup-label">' + $el.prop('label') + '</div>';
                                choices += $this.buildOptions($el);
                                choices += '</div>';
                            }
                            else {
                                var selected = $el.is('[selected]') ? ' selected' : '';
                                choices += '<div class="fs-option' + selected + '" data-value="' + $el.prop('value') + '"><span class="fs-checkbox"><i></i></span><div class="fs-option-label">' + $el.html() + '</div></div>';
                            }
                        });

                        return choices;
                    },

                    reloadDropdownLabel: function () {
                        var settings = this.settings;
                        var labelText = [];

                        this.$wrap.find('.fs-option.selected').each(function (i, el) {
                            labelText.push($(el).find('.fs-option-label').text());
                        });

                        if (labelText.length < 1) {
                            labelText = settings.placeholder;
                        }
                        else if (labelText.length > settings.numDisplayed) {
                            labelText = settings.overflowText.replace('{n}', labelText.length);
                        }
                        else {
                            labelText = labelText.join(', ');
                        }

                        this.$wrap.find('.fs-label').html(labelText);
                        this.$select.change();
                    }
                }


                /**
                 * Loop through each matching element
                 */
                return this.each(function () {
                    var data = $(this).data('fSelect');

                    if (!data) {
                        data = new fSelect(this, settings);
                        $(this).data('fSelect', data);
                    }

                    if (typeof settings == 'string') {
                        data[settings]();
                    }
                });
            }


            /**
             * Events
             */
            window.fSelect = {
                'active': null,
                'idx': -1
            };

            function setIndexes($wrap) {
                $wrap.find('.fs-option:not(.hidden)').each(function (i, el) {
                    $(el).attr('data-index', i);
                    $wrap.find('.fs-option').removeClass('hl');
                });
                $wrap.find('.fs-search input').focus();
                window.fSelect.idx = -1;
            }

            function setScroll($wrap) {
                var $container = $wrap.find('.fs-options');
                var $selected = $wrap.find('.fs-option.hl');

                var itemMin = $selected.offset().top + $container.scrollTop();
                var itemMax = itemMin + $selected.outerHeight();
                var containerMin = $container.offset().top + $container.scrollTop();
                var containerMax = containerMin + $container.outerHeight();

                if (itemMax > containerMax) { // scroll down
                    var to = $container.scrollTop() + itemMax - containerMax;
                    $container.scrollTop(to);
                }
                else if (itemMin < containerMin) { // scroll up
                    var to = $container.scrollTop() - containerMin - itemMin;
                    $container.scrollTop(to);
                }
            }

            $(document).on('click', '.fs-option', function () {
                var $wrap = $(this).closest('.fs-wrap');

                if ($wrap.hasClass('multiple')) {
                    var selected = [];

                    $(this).toggleClass('selected');
                    $wrap.find('.fs-option.selected').each(function (i, el) {
                        selected.push($(el).attr('data-value'));
                    });
                }
                else {
                    var selected = $(this).attr('data-value');
                    $wrap.find('.fs-option').removeClass('selected');
                    $(this).addClass('selected');
                    $wrap.find('.fs-dropdown').hide();
                }

                $wrap.find('select').val(selected);
                $wrap.find('select').fSelect('reloadDropdownLabel');
            });

            $(document).on('keyup', '.fs-search input', function (e) {
                if (40 == e.which) {
                    $(this).blur();
                    return;
                }

                var $wrap = $(this).closest('.fs-wrap');
                var keywords = $(this).val();

                $wrap.find('.fs-option, .fs-optgroup-label').removeClass('hidden');

                if ('' != keywords) {
                    $wrap.find('.fs-option').each(function () {
                        var regex = new RegExp(keywords, 'gi');
                        if (null === $(this).find('.fs-option-label').text().match(regex)) {
                            $(this).addClass('hidden');
                        }
                    });

                    $wrap.find('.fs-optgroup-label').each(function () {
                        var num_visible = $(this).closest('.fs-optgroup').find('.fs-option:not(.hidden)').length;
                        if (num_visible < 1) {
                            $(this).addClass('hidden');
                        }
                    });
                }

                setIndexes($wrap);
            });

            $(document).on('click', function (e) {
                var $el = $(e.target);
                var $wrap = $el.closest('.fs-wrap');

                if (0 < $wrap.length) {
                    if ($el.hasClass('fs-label')) {
                        window.fSelect.active = $wrap;
                        var is_hidden = $wrap.find('.fs-dropdown').hasClass('hidden');
                        $('.fs-dropdown').addClass('hidden');

                        if (is_hidden) {
                            $wrap.find('.fs-dropdown').removeClass('hidden');
                        }
                        else {
                            $wrap.find('.fs-dropdown').addClass('hidden');
                        }

                        setIndexes($wrap);
                    }
                }
                else {
                    $('.fs-dropdown').addClass('hidden');
                    window.fSelect.active = null;
                }
            });

            $(document).on('keydown', function (e) {
                var $wrap = window.fSelect.active;

                if (null === $wrap) {
                    return;
                }
                else if (38 == e.which) { // up
                    e.preventDefault();

                    $wrap.find('.fs-option').removeClass('hl');

                    if (window.fSelect.idx > 0) {
                        window.fSelect.idx--;
                        $wrap.find('.fs-option[data-index=' + window.fSelect.idx + ']').addClass('hl');
                        setScroll($wrap);
                    }
                    else {
                        window.fSelect.idx = -1;
                        $wrap.find('.fs-search input').focus();
                    }
                }
                else if (40 == e.which) { // down
                    e.preventDefault();

                    var last_index = $wrap.find('.fs-option:last').attr('data-index');
                    if (window.fSelect.idx < parseInt(last_index)) {
                        window.fSelect.idx++;
                        $wrap.find('.fs-option').removeClass('hl');
                        $wrap.find('.fs-option[data-index=' + window.fSelect.idx + ']').addClass('hl');
                        setScroll($wrap);
                    }
                }
                else if (32 == e.which || 13 == e.which) { // space, enter
                    $wrap.find('.fs-option.hl').click();
                }
                else if (27 == e.which) { // esc
                    $('.fs-dropdown').addClass('hidden');
                    window.fSelect.active = null;
                }
            });

        })(jQuery);
    </script>
</div>

</body>
</html>

猜你喜欢

转载自blog.csdn.net/qq_40012791/article/details/80191381
今日推荐