Jquery UI自动完成combobox按钮单击事件

使用jquery ui自动完成function创建combobox时,我遇到了奇怪的行为。 每当我点击滚动条滚动结果列表然后单击我的combobox按钮关闭结果列表关闭结果然后再次打开。 我希望它关闭菜单。

Repro的步骤

  1. 打开jsfiddle演示
  2. 在自动完成中键入“i”或按下下拉按钮。
  3. 单击垂直滚动以滚动结果
  4. 单击下拉按钮

创建按钮的脚本

this.button = $("") .attr({ "tabIndex": -1, "title": "Show all items" }) .insertAfter(input) .button({ icons: { primary: "ui-icon-triangle-1-s" }, text: false }) .removeClass("ui-corner-all") .addClass("ui-corner-right ui-button-icon") .click(function () { // when i put breakpoint here, and my focus is not on input, // then this if steatment is false???? if (input.autocomplete("widget").is(":visible")) { input.autocomplete("close"); return; } // work around a bug (likely same cause as #5265) $(this).blur(); // pass empty string as value to search for, displaying all results input.autocomplete("search", ""); input.focus(); }); 

CSS(强制滚动结果菜单)

 .ui-autocomplete { max-height: 100px; overflow-y: auto; /* prevent horizontal scrollbar */ overflow-x: hidden; /* add padding to account for vertical scrollbar */ padding-right: 20px; } /* IE 6 doesn't support max-height * we use height instead, but this forces the menu to always be this tall */ * html .ui-autocomplete { height: 100px; } 

即使焦点转移到小部件本身而不是输入元素,我的解决方案可能是关闭小部件?

任何想法如何修改此代码,以便它以这种方式行事?

根据自动完成小部件的各种点击和鼠标事件的问题,我想出了这个: jsFiddle示例

jQuery的:

 var input = $('#txtComplete'); var data = []; var isOpen = false; function _init() { for (var idx = 0; idx <= 100; idx++) { data.push('item: ' + idx); }; input.autocomplete({ source: data, minLength: 0, open: function(event, ui) { isOpen = true; }, select: function(event, ui) { isOpen = false; } }); } function afterInit() { var button = $("").attr("tabIndex", -1).attr("title", "Show all items").insertAfter(input).button({ icons: { primary: "ui-icon-triangle-1-s" }, text: false }).removeClass("ui-corner-all").addClass("ui-corner-right ui-button-icon").click(function(event) { input.focus(); if (isOpen) { input.autocomplete("close"); isOpen = false; } else { input.autocomplete("search", ""); event.stopImmediatePropagation(); } }); } $(window).click(function() { input.autocomplete("close"); isOpen = false; }); $(function() { _init(); afterInit(); });​ 

问题是因为在jquery ui自动完成中的解决方法。 在某些条件下,有一个mousedown事件设置可以关闭菜单。 在其中一个条件中,它会检查引发mousedown的项是否是自动完成小部件的一部分。 如果没有,它会关闭菜单。 由于您正在处理combobox行为并且您的按钮不是自动完成小部件的一部分,因此单击该按钮会因此事件而关闭菜单。

您可以在github上的自动完成源中的第205行开始查看违规情况。 可能值得在jquery ui论坛上提出这个问题,因为他们的combobox演示也有这个bug。

UPDATE

此替换事件基于jquery-ui 1.8.18。 此事件已发生变化,很可能会再次发生变化。 如果您采用此路线,则可能需要使用每个版本手动更新此代码。

如果是在创建自动完成后运行以下内容而单击的组合按钮,则可以修补mousedown事件以不关闭菜单( jsfiddle演示 )。

 var input = $('#combotextbox').autocomplete(/*options*/); input.data('autocomplete').menu.element.unbind('mousedown').mousedown(function(event) { var self = input.data('autocomplete'); event.preventDefault(); // clicking on the scrollbar causes focus to shift to the body // but we can't detect a mouseup or a click immediately afterward // so we have to track the next mousedown and close the menu if // the user clicks somewhere outside of the autocomplete var menuElement = self.menu.element[0]; if (!$(event.target).closest(".ui-menu-item").length) { setTimeout(function() { $(document).one('mousedown', function(event) { var t = $(event.target); if (event.target !== self.element[0] && event.target !== menuElement && !$.ui.contains(menuElement, event.target) && !t.hasClass('ui-combo-trigger') && !t.parent().hasClass('ui-combo-trigger')) { self.close(); } }); }, 1); } // use another timeout to make sure the blur-event-handler on the input was already triggered setTimeout(function() { clearTimeout(self.closing); }, 13); }); 

这将删除当前的mousedown事件,然后通过添加的检查将其添加回来,以查看触发事件的元素或其父元素(单击按钮中的按钮或按钮内的ui-icon)是否具有类ui-combo-trigger

创建按钮的代码相对不变。 我们只需要添加新类ui-combo-trigger

 var button = $("").attr("tabIndex", -1).attr("title", "Show all items").insertAfter(input).button({ icons: { primary: "ui-icon-triangle-1-s" }, text: false }).removeClass("ui-corner-all").addClass("ui-corner-right ui-button-icon ui-combo-trigger").click(function(event) { // when i put breakpoint here, and my focus is not on input, // then this if steatment is false???? if (input.autocomplete("widget").is(":visible")) { input.autocomplete("close"); return; } // work around a bug (likely same cause as #5265) $(this).blur(); // pass empty string as value to search for, displaying all results input.autocomplete("search", ""); input.focus(); event.stopImmediatePropagation(); }); 

试试这个jsfiddle 。 我想它会帮助你。

 var input = $('#txtComplete'); var data = []; var openCheck = false; function _init() { for (var idx = 0; idx <= 100; idx++) { data.push('item: ' + idx); }; input.autocomplete({ source: data, minLength: 0, open: function(event, ui) { openCheck = true; }, select: function(event, ui) { openCheck = false; } }); } function afterInit() { var button = $("").attr("tabIndex", -1).attr("title", "Show all items").insertAfter(input).button({ icons: { primary: "ui-icon-triangle-1-s" }, text: false }).removeClass("ui-corner-all").addClass("ui-corner-right ui-button-icon").click(function(event) { if (openCheck) { input.autocomplete("close"); openCheck = false; } else { input.autocomplete("search", ""); } }); } $(function() { _init(); afterInit(); }); 

Brian解释这个问题非常好。 使用jquery ui 11,您可以执行以下操作:

 wasOpen = false; $button .mousedown(function() { wasOpen = input.autocomplete( "widget" ).is( ":visible" ); }) .click(function() { input.focus(); // Close if already visible if ( wasOpen ) { return; } 

请参阅http://jqueryui.com/autocomplete/#combobox上的示例