javascript Jquery UI 自动完成组合框按钮单击事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10227171/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 09:07:21  来源:igfitidea点击:

Jquery UI autocomplete combobox button click event

javascriptjqueryjquery-uicomboboxjquery-autocomplete

提问by Davor Zubak

I'm experiencing weird behavior with jquery ui autocomplete when using it to create a combobox. Whenever I click on the scrollbar to scroll through the list of results AND then click on my combobox button to close the results the results list closes and then opens again. I expect it to close the menu.

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

Steps to Repro

重现步骤

  1. open jsfiddle demo
  2. Type 'i' in the autocomplete OR hit the dropdown button.
  3. Click on the vertical scroll to scroll the results
  4. Click on the dropdown button
  1. 打开jsfiddle演示
  2. 在自动完成中输入“i”或点击下拉按钮。
  3. 单击垂直滚动可滚动结果
  4. 单击下拉按钮

Script to Create Button

创建按钮的脚本

 this.button = $("<button type='button'>&nbsp;</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 (force long results menu to scroll)

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;
}

My solution could be closing the widget even if focus is transferred to widget itself and not the input element?

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

Any ideas how to modify this code so it behaves this way?

任何想法如何修改此代码使其行为如此?

采纳答案by j08691

Based on issues with the various click and mouse events for the automplete widget, I came up with this: jsFiddle example.

基于自动完成小部件的各种点击和鼠标事件的问题,我想出了这个:jsFiddle example

jQuery:

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 = $("<button type='button'>&nbsp;</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();
});?

回答by Brian Cauthon

The problem is because of a work around in jquery ui autocomplete. There is a mousedown event setup to close the menu under certain conditions. In one of the conditions it checks to see if the item that raised the mousedown is part of the autocomplete widget. If not, it closes the menu. Since you are tacking on combobox behaviour and your button is not part of the autocomplete widget, a click on the button is closing the menu because of this event.

问题是因为 jquery ui 自动完成中的一个变通方法。有一个 mousedown 事件设置可以在某些条件下关闭菜单。在其中一种情况下,它会检查引发鼠标按下的项目是否是自动完成小部件的一部分。如果没有,它将关闭菜单。由于您正在处理组合框行为并且您的按钮不是自动完成小部件的一部分,因此由于此事件,单击按钮会关闭菜单。

You can see the offending condition with the reason why it is there starting at line 205 in the autocomplete source on github. It is probably worth raising the issue on the jquery ui forums since their combobox demo has this bug too.

您可以在 github 上自动完成源中从第 205 行开始查看违规条件及其原因。在 jquery ui 论坛上提出这个问题可能是值得的,因为他们的组合框演示也有这个错误。

UPDATE

更新

This replacement event is based off of jquery-ui 1.8.18. This event has changed and will very likely change again. You might need to update this code manually with each release if you go this route.

此替换事件基于 jquery-ui 1.8.18。此事件已更改,并且很可能会再次更改。如果您走这条路线,您可能需要在每个版本中手动更新此代码。

You can patch the mousedownevent to not close the menu if it was your combo button that was clicked by running the following after you create your autocomplete (jsfiddle demo).

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);
    });

This removes the current mousedown event and then adds it back in with an added check to see if the element that triggered the event or its parent (button clicked or ui-icon inside the button is clicked) has a class ui-combo-trigger.

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

The code to create your button is relatively unchanged. We just need to add the new class ui-combo-trigger.

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

var button = $("<button type='button'>&nbsp;</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();
    });

回答by lakshmi priya

Try this jsfiddle. I think it ll help you.

试试这个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 = $("<button type='button'>&nbsp;</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();
});

回答by Dominik

Brian explained the problem very good. With jquery ui 11 you can do something like:

布赖恩很好地解释了这个问题。使用 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;
        }

see example at http://jqueryui.com/autocomplete/#combobox

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