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

15
我在使用jquery ui autocomplete创建combobox时遇到了奇怪的问题。每当我点击滚动条以滚动结果列表,然后再点击我的combobox按钮关闭结果时,结果列表会关闭,然后再次打开。我希望它能关闭菜单。

复现步骤

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

创建按钮的脚本

 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(强制长结果菜单滚动)
.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;
}

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

有什么想法可以修改这个代码以使其行为如此?


你能提供HTML代码,或者JSFiddle链接吗?这样会更容易理解。 - Allan Kimmer Jensen
我不明白你在这里尝试实现什么.. jsfiddle - Justin Obney
你实际上想要解决什么问题? - Andrew Whitaker
我的问题是,当我点击按钮小部件时,下拉菜单小部件出现,然后我再次点击小部件上的按钮,我的小部件被重新创建而不是关闭。我希望我的下拉菜单小部件可以以切换方式打开和关闭! - Davor Zubak
4个回答

5

基于自动完成小部件的各种单击和鼠标事件问题,我想到了这个: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 = $("<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();
});​

@lakshmipriya - 是的,没问题,可以正常工作。 - j08691
无法再使用箭头键浏览列表。 - Brian Cauthon
@j08691 非常感谢,这太棒了。 - patrick

3
问题出在jquery ui自动完成中的一个解决方法。设置了一个mousedown事件来在特定条件下关闭菜单。在其中一个条件中,它检查引发mousedown的项目是否是自动完成小部件的一部分。如果不是,则关闭菜单。由于您正在添加组合框行为,而按钮不是自动完成小部件的一部分,因此单击按钮会因为此事件而关闭菜单。
您可以在github上的自动完成源代码的第205行开始看到有问题的条件及其原因。由于他们的组合框演示也存在此错误,因此可能值得在jquery ui论坛上提出此问题。
更新:
此替换事件基于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 = $("<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();
    });

1

试试这个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();
});

无法再使用箭头键浏览列表。 - Brian Cauthon

0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接