Как перезагрузить объект jQuery dropkick


Я использую простой список выбора и jquery.библиотека dropkick, чтобы сделать его красивым. Теперь я хочу изменить это содержимое dropkick после того, как соответствующий элемент select был изменен (появилась новая опция). Но просто вызов $('#select').dropkick (); не работает.

И похоже, что он не поддерживается. Было бы достаточно просто восстановить этот дропкик с нуля. Есть ли возможность "уничтожить" этот объект dropkick, а затем восстановить его, вызвав .пнуть() метод?

6 8

6 ответов:

Я столкнулся с той же проблемой и не мог найти решение, но в конце концов преуспел в получении этой халтуры.

$select = $("#select1");
$select.removeData("dropkick");
$("#dk_container_select1").remove();

$select.append("<option>opt4</option>");
$select.append("<option>opt5</option>");

$select.dropkick();

Я воспользовался ответом диода, чтобы изменить код Dropkick, чтобы сделать его немного чище:

// Reload the dropkick select widget after options have changed
// usage: $("...").dropkick('reload');
methods.reload = function () {
    var $select = $(this);
    var data = $select.data('dropkick');
    $select.removeData("dropkick");
    $("#dk_container_"+ data.id).remove();
    $select.dropkick(data.settings);
};

Добавьте приведенный выше код сразу после следующего фрагмента в dropkick.js:

methods.reset = function () {
  ...
};

Тогда вы можете использовать его программно:

    $('#my-select').html("<option>new options</option>");
    $('#my-select').dropkick('reload');

Для еще более новых посетителей. Dropkick использует метод reset...не перерисовывать.

$("select").dropkick('reset');

Я столкнулся с той же проблемой, я сделал некоторые исправления к сценарию jquery-dropkick-1.0.0, чтобы решить эту проблему. Я добавил метод forceSyncWithSelect к объекту dropkick.

Вот список изменений, которые я сделал:

  • добавить поддержку тега
  • Добавьте настройки autoWidth, чтобы оставить ширину css
  • добавить метод для open, close, forceSyncWithSelect и isDropkicked
  • сохранить табиндекс по умолчанию 0
  • Добавьте опцию класса optgroup с помощью data-dkgroupclass атрибут элемента optgroup
  • исправьте метод forceSyncWithSelect, если значение появляется кратным времени, возьмите только первое вхождение
  • включение нажмите на кнопку выбора меню
  • запретить IE закрывать меню при взаимодействии с полосой прокрутки (при взаимодействии с полосой прокрутки запускается событие размытия, это поведение настолько неправильно)

Вы можете не хотеть все эти изменения, но вы можете сделать diff патч и взять то, что вам нужно (был бы рад, если бы вы позволили журнал изменений или добавить источник это в заголовке, я хочу предложить эти изменения на Джейми Lottering, но мне нужно сделать аккаунт git-концентратор, чтобы сделать так.

/**
 * DropKick
 *
 * Highly customizable <select> lists
 * https://github.com/JamieLottering/DropKick
 *
 * &copy; 2011 Jamie Lottering <http://github.com/JamieLottering>
 *                        <http://twitter.com/JamieLottering>
 *
 * Patch:
 *  - 2012-03-30 godboutj, add support for <optgroup> tag
 *  - 2012-03-30 godboutj, add autoWidth settings to leave width to css
 *  - 2012-05-25 godboutj, add method for open, close, forceSyncWithSelect and isDropkicked
 *  - 2012-05-25 godboutj, keep default tabindex 0
 *  - 2012-08-09 godboutj, add optgroup class option with the data-dkgroupclass attribute on optgroup element
 *  - 2012-08-15 godboutj, fix forceSyncWithSelect method if value appear multiple of time, take the first occurrence only
 *  - 2012-09-07 godboutj, toggle on click on the menu selection
 *  - 2012-09-25 godboutj, prevent IE from closing the menu on scroll bar interaction (a blur event is launched on scroll bar interaction, this behavior is so wrong)
 */
(function ($, window, document)
{

    var ie6 = false;

    // Help prevent flashes of unstyled content
    if ($.browser.msie && $.browser.version.substr(0, 1) < 7)
    {
        ie6 = true;
    } else
    {
        document.documentElement.className = document.documentElement.className + ' dk_fouc';
    }

    var 
    // Public methods exposed to $.fn.dropkick()
    methods = {},

    // Cache every <select> element that gets dropkicked
    lists = [],

    // Convenience keys for keyboard navigation
    keyMap = {
        'left': 37,
        'up': 38,
        'right': 39,
        'down': 40,
        'enter': 13
    },

    // HTML template for the dropdowns
    dropdownTemplate = [
      '<div class="dk_container" id="dk_container_{{ id }}" tabindex="{{ tabindex }}">',
        '<a class="dk_toggle">',
          '<span class="dk_label">{{ label }}</span>',
        '</a>',
        '<div class="dk_options">',
          '<ul class="dk_options_inner">',
          '</ul>',
        '</div>',
      '</div>'
    ].join(''),

    // HTML template for dropdown options
    optionTemplate = '<li class="{{ current }}"><a data-dk-dropdown-value="{{ value }}">{{ text }}</a></li>',
    optionGroupTemplate = '<li class="dk_option_group {{ dataclass }}"><div class="dk_option_group_text">{{ text }}</div></li>',

    // Some nice default values
    defaults = {
        startSpeed: 1000,  // I recommend a high value here, I feel it makes the changes less noticeable to the user
        theme: false,
        change: false,
        autoWidth: true
    },

    // Make sure we only bind keydown on the document once
    keysBound = false
  ;

    // Called by using $('foo').dropkick();
    methods.init = function (settings)
    {
        settings = $.extend({}, defaults, settings);

        return this.each(function ()
        {
            var 
            // The current <select> element
            $select = $(this),

            // Store a reference to the originally selected <option> element
            $original = $select.find(':selected').first(),

            // Save all of the <option> and <optgroup> elements
            $options = $select.children('option,optgroup'),

            // We store lots of great stuff using jQuery data
            data = $select.data('dropkick') || {},

            // This gets applied to the 'dk_container' element
            id = $select.attr('id') || $select.attr('name'),

            // This gets updated to be equal to the longest <option> element
            width = settings.width || $select.outerWidth(),

            // Keep tabindex, even default value
            tabindex = ($select.attr('tabindex') != null && $select.attr('tabindex') != undefined) ? $select.attr('tabindex') : '',

            // The completed dk_container element
            $dk = false,

            theme
      ;

            // Dont do anything if we've already setup dropkick on this element
            if (data.id)
            {
                return $select;
            }
            else
            {
                data.settings = settings;
                data.tabindex = tabindex;
                data.id = id;
                data.$original = $original;
                data.$select = $select;
                data.value = _notBlank($select.val()) || _notBlank($original.attr('value'));
                data.label = $original.text();
                data.options = $options;
            }

            // Build the dropdown HTML
            $dk = _build(dropdownTemplate, data);

            // Make the dropdown fixed width if desired
            if (settings.autoWidth)
            {
                $dk.find('.dk_toggle').css({
                    'width': width + 'px'
                });
            }
            // Hide the <select> list and place our new one in front of it
            $select.before($dk);

            // Update the reference to $dk
            $dk = $('#dk_container_' + id).fadeIn(settings.startSpeed);

            // Save the current theme
            theme = settings.theme ? settings.theme : 'default';
            $dk.addClass('dk_theme_' + theme);
            data.theme = theme;

            // Save the updated $dk reference into our data object
            data.$dk = $dk;

            // Save the dropkick data onto the <select> element
            $select.data('dropkick', data);

            // Do the same for the dropdown, but add a few helpers
            $dk.data('dropkick', data);

            lists[lists.length] = $select;

            // Focus events
            $dk.bind('focus.dropkick', function (e)
            {
                $dk.addClass('dk_focus');
            }).bind('blur.dropkick', function (e)
            {
                // Prevent IE from closing the menu on focus loose, 
                // this make the menu close all the time when using the scroll bar
                if (!$.browser.msie)
                {
                    $dk.removeClass('dk_open');
                }
                $dk.removeClass('dk_focus');
            });

            setTimeout(function ()
            {
                $select.hide();
            }, 0);
        });
    };

    // Allows dynamic theme changes
    methods.theme = function (newTheme)
    {
        var 
      $select = $(this),
      list = $select.data('dropkick'),
      $dk = list.$dk,
      oldtheme = 'dk_theme_' + list.theme
    ;

        $dk.removeClass(oldtheme).addClass('dk_theme_' + newTheme);

        list.theme = newTheme;
    };

    // Force Value sync
    methods.forceSyncWithSelect = function ()
    {
        var 
            $select = $(this),
            $dk = $select.data('dropkick').$dk,
            $current = $dk.find("li [data-dk-dropdown-value='" + $select.val() + "']").first()
        ;
        _updateFields($current, $dk, true);
    };

    // Reset all <selects and dropdowns in our lists array
    methods.reset = function ()
    {
        for (var i = 0, l = lists.length; i < l; i++)
        {
            var 
        listData = lists[i].data('dropkick'),
        $dk = listData.$dk,
        $current = $dk.find('li').first()
      ;

            $dk.find('.dk_label').text(listData.label);
            $dk.find('.dk_options_inner').animate({ scrollTop: 0 }, 0);

            _setCurrent($current, $dk);
            _updateFields($current, $dk, true);
        }
    };

    methods.close = function ()
    {
        var 
            $select = $(this),
            $dk = $select.data('dropkick').$dk
        ;
        _closeDropdown($dk);
    }

    methods.open = function ()
    {
        var 
            $select = $(this),
            $dk = $select.data('dropkick').$dk
        ;
        _openDropdown($dk);
    }

    methods.isOpen = function ()
    {
        var 
            $select = $(this),
            $dk = $select.data('dropkick').$dk
        ;
        return _isDropdownOpenned($dk);
    }

    methods.toggleOpen = function ()
    {
        var 
            $select = $(this),
            $dk = $select.data('dropkick').$dk
        ;
        _toggleOpenCloseDropDown($dk);
    }

    methods.isDropkicked = function ()
    {
        var $select = $(this);
        return $select.data('dropkick') != undefined;
    }

    // Expose the plugin
    $.fn.dropkick = function (method)
    {
        if (!ie6)
        {
            if (methods[method])
            {
                return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
            } else if (typeof method === 'object' || !method)
            {
                return methods.init.apply(this, arguments);
            }
        }
    };

    // private
    function _handleKeyBoardNav(e, $dk)
    {
        var 
      code = e.keyCode,
      data = $dk.data('dropkick'),
      options = $dk.find('.dk_options'),
      open = $dk.hasClass('dk_open'),
      current = $dk.find('.dk_option_current'),
      first = options.find('li').first(),
      last = options.find('li').last(),
      next,
      prev
    ;

        switch (code)
        {
            case keyMap.enter:
                if (open)
                {
                    _updateFields(current.find('a'), $dk);
                    _closeDropdown($dk);
                } else
                {
                    _openDropdown($dk);
                }
                e.preventDefault();
                break;

            case keyMap.up:
                prev = current.prev('li');
                if (open)
                {
                    if (prev.length)
                    {
                        _setCurrent(prev, $dk);
                    } else
                    {
                        _setCurrent(last, $dk);
                    }
                } else
                {
                    _openDropdown($dk);
                }
                e.preventDefault();
                break;

            case keyMap.down:
                if (open)
                {
                    next = current.next('li').first();
                    if (next.length)
                    {
                        _setCurrent(next, $dk);
                    } else
                    {
                        _setCurrent(first, $dk);
                    }
                } else
                {
                    _openDropdown($dk);
                }
                e.preventDefault();
                break;

            default:
                break;
        }
    }

    // Update the <select> value, and the dropdown label
    function _updateFields(option, $dk, reset)
    {
        var value, label, data;

        value = option.attr('data-dk-dropdown-value');
        label = option.text();
        data = $dk.data('dropkick');

        $select = data.$select;
        $select.val(value);

        $dk.find('.dk_label').text(label);

        reset = reset || false;

        if (data.settings.change && !reset)
        {
            data.settings.change.call($select, value, label);
        }
    }

    // Set the currently selected option
    function _setCurrent($current, $dk)
    {
        $dk.find('.dk_option_current').removeClass('dk_option_current');
        $current.addClass('dk_option_current');

        _setScrollPos($dk, $current);
    }

    function _setScrollPos($dk, anchor)
    {
        var height = anchor.prevAll('li').outerHeight() * anchor.prevAll('li').length;
        $dk.find('.dk_options_inner').animate({ scrollTop: height + 'px' }, 0);
    }

    // Is dropdown openned function 
    function _isDropdownOpenned($dk)
    {
        return $dk.hasClass('dk_open');
    }

    // Close a dropdown
    function _closeDropdown($dk)
    {
        $dk.removeClass('dk_open');
    }

    // Open a dropdown
    function _openDropdown($dk)
    {
        var data = $dk.data('dropkick');
        $dk.find('.dk_options').css({ top: $dk.find('.dk_toggle').outerHeight() - 1 });
        if (!$dk.hasClass('dk_open'))
        {
            $dk.addClass('dk_open');
        }
    }

    // Toggle dropdown
    function _toggleOpenCloseDropDown($dk)
    {
        if (_isDropdownOpenned($dk))
        {
            _closeDropdown($dk);
        }
        else
        {
            _openDropdown($dk);
        }
    }

    /**
    * Turn the dropdownTemplate into a jQuery object and fill in the variables.
    */
    function _build(tpl, view)
    {
        var 
        // Template for the dropdown
            template = tpl,
        // Holder of the dropdowns options
            options = [],
            $dk
        ;

        template = template.replace('{{ id }}', view.id);
        template = template.replace('{{ label }}', view.label);
        template = template.replace('{{ tabindex }}', view.tabindex);

        if (view.options && view.options.length)
        {
            for (var i = 0, l = view.options.length; i < l; i++)
            {
                var 
                  $option = $(view.options[i]),
                  current = 'dk_option_current',
                  oTemplate = optionTemplate,
                  gTemplate = optionGroupTemplate
                ;

                if ($option.is('optgroup'))
                {
                    gTemplate = gTemplate.replace('{{ text }}', $option.attr('label'));
                    if ($option.attr('data-dkgroupclass') != undefined)
                    {
                        gTemplate = gTemplate.replace('{{ dataclass }}', $option.attr('data-dkgroupclass'));
                    }
                    // Support only one level as per W3C standard
                    $option.children('option').each(
                        function (index, element)
                        {
                            oTemplate = optionTemplate,
                            oTemplate = oTemplate.replace('{{ value }}', $(element).val());
                            oTemplate = oTemplate.replace('{{ current }}', (_notBlank($(element).val()) === view.value) ? current : '');
                            oTemplate = oTemplate.replace('{{ text }}', $(element).text());
                            gTemplate += oTemplate;
                        }
                    );

                    options[options.length] = gTemplate;
                }
                else
                {
                    oTemplate = oTemplate.replace('{{ value }}', $option.val());
                    oTemplate = oTemplate.replace('{{ current }}', (_notBlank($option.val()) === view.value) ? current : '');
                    oTemplate = oTemplate.replace('{{ text }}', $option.text());

                    options[options.length] = oTemplate;
                }
            }
        }

        $dk = $(template);
        $dk.find('.dk_options_inner').html(options.join(''));

        return $dk;
    }

    function _notBlank(text)
    {
        return ($.trim(text).length > 0) ? text : false;
    }

    $(function ()
    {

        // Handle click events on the dropdown toggler
        $('.dk_toggle').live('click', function (e)
        {
            var $dk = $(this).parents('.dk_container').first();

            _toggleOpenCloseDropDown($dk);

            if ("ontouchstart" in window)
            {
                $dk.addClass('dk_touch');
                $dk.find('.dk_options_inner').addClass('scrollable vertical');
            }

            e.preventDefault();
            return false;
        });

        // Handle click events on individual dropdown options
        $('.dk_options a').live(($.browser.msie ? 'mousedown' : 'click'), function (e)
        {
            var 
        $option = $(this),
        $dk = $option.parents('.dk_container').first(),
        data = $dk.data('dropkick')
      ;

            _closeDropdown($dk);
            _updateFields($option, $dk);
            _setCurrent($option.parent(), $dk);

            e.preventDefault();
            return false;
        });

        // Setup keyboard nav
        $(document).bind('keydown.dk_nav', function (e)
        {
            var 
            // Look for an open dropdown...
        $open = $('.dk_container.dk_open'),

            // Look for a focused dropdown
        $focused = $('.dk_container.dk_focus'),

            // Will be either $open, $focused, or null
        $dk = null
      ;

            // If we have an open dropdown, key events should get sent to that one
            if ($open.length)
            {
                $dk = $open;
            } else if ($focused.length && !$open.length)
            {
                // But if we have no open dropdowns, use the focused dropdown instead
                $dk = $focused;
            }

            if ($dk)
            {
                _handleKeyBoardNav(e, $dk);
            }
        });
    });
})(jQuery, window, document);

Для новых посетителей. Dropkick добавил метод перерисовки.

$("select").dropkick('redraw');
$('#select').html('<option>a</option>').dropkick('refresh');