jQuery自动完成'焦点'事件触发,但没有反向等效。我徘徊离开,但变化仍然存在

时间:2013-02-07 23:47:44

标签: javascript jquery jquery-ui autocomplete

简而言之,jQuery-ui自动完成具有“焦点”事件(实际上是悬停事件),当用户将鼠标悬停在自动完成菜单选项上时会触发该事件。但如果用户在没有做出选择的情况下继续打字,那就没有相应的功能。

这是 fiddle ,如果有帮助的话。


编辑问题以提供下面完整阐述的简短版本的解决方案(以及下面的小提琴)

只要用户离开菜单(通过鼠标或键盘),此解决方案就会反转焦点功能,并且只要用户首先进行选择,就会反转,然后改变输入字段。


$( "#id-input" ).autocomplete({
.....
focus: function( event, ui ) {
    .... do foo ......
    $('li.special-class').one ("mouseleave", function() {
        .... undo foo .....
    });
},
select: function( event, ui ) {
    $('li.special-class').off("mouseleave");
    .... do foo ....
    $( "#id-input" ).one ("keypress", function (e) {
        if (e.keyCode !== 13) {
        // Keyboard select is ignored, otherwise messing with input undoes foo
            .... undo foo ....
        }
        else {
            $( "#id-input" ).one ("keypress", function (e) {
            // Re-establish key binding if original select was keyboard
                if (e.keyCode !== 13) {
                    .... undo foo ....
                }
            })

        }
    })
}
});
// override the built-in _renderItem to put a special class in all menu items
$( "#id_input" ).data("uiAutocomplete")._renderItem = function( ul, item ) {
return $( "<li class='special-class'></li>" )
.append( "<a>" + item.label + "</a>" )
.appendTo( ul );
};
// override the built-in _move function for keyboard up/down that leaves the menu
$( "#id_input" ).data( "uiAutocomplete" )._move = function( direction, event ) {
if ( !this.menu.element.is( ":visible" ) ) {
    this.search( null, event );
    return;
}
if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
        this.menu.isLastItem() && /^next/.test( direction ) ) {
    this._value( this.term );
    .... undo foo ....
    return;
}
this.menu[ direction ]( event );
};

3 个答案:

答案 0 :(得分:3)

这里是 fiddle for the solution

底部的代码

http://jsfiddle.net/R68jf/5/

感谢Red October的Capt.Marco Ramius让我意识到解决原始问题的方法。 &#34;仅限一个Ping&#34; ....如下所述。

这个http://jsfiddle.net/R68jf/5/小提琴提供了一个有效的解决方案,并向ui-autocomplete小部件展示了一些有用的自定义,这可能有助于解决其他问题。具体而言,该解决方案满足以下要求:

1)每当用户使用鼠标或键盘浏览自动完成菜单项时,“焦点”#39;触发回调,在这种情况下显示附加信息和链接图像。这是正常的自动完成行为,在API中公开并记录。

2)每当用户从菜单中向外或向外导航时,“焦点”的效果都会消失。回调应该是可逆的。这不是默认行为,目前没有&#39;模糊&#39; API旨在消除“焦点”的副作用。因此,&#39; zombie&#39;虽然菜单项不再处于焦点状态,但图像仍然存在。最初的问题小提示显示此默认值和相关的“僵尸”#39;影响。要查看它,只需输入“垃圾邮件”即可。然后在菜单中向上和向下滚动。滚动时,副作用会更新。现在鼠标离开菜单......僵尸留下!!

3)如果用户在焦点项目上进行选择,使用鼠标单击或返回键,则与该项目焦点相关的副作用应该保持不变。这很容易,通过使用&#39; select&#39;在文档化的API中公开的方法。

4)如果在进行菜单选择后,用户返回搜索输入并更改搜索,则应反转副作用。这不是默认情况下发生的,而是我们有僵尸!

为了达到这些要求,我采用了以下方法。对于我们中较为高级的人来说,这些看起来可能是基本的,但对于我的薪水等级的其他人来说,这可能是ui-autocomplete定制的有用证明:

1)覆盖自动完成的_renderItem方法以自定义菜单显示。

2)当使用键盘离开菜单时,覆盖_move方法以改变行为。

3)使用一些&#39; Red October&#39;灵感来自“仅限一平”#39;回调,反转焦点副作用,然后将系统返回到其原始就绪状态。这使用了jQuery .one()方法。

这里的代码评论很多,但值得一提的是:

1)某些事件,例如从菜单中选择项目然后关闭菜单,将自动触发菜单上的模糊和鼠标移除事件,作为其自然行为的一部分。这可能是一个问题,因为在当前的例子中,我想要一个模糊的&#39;杀死所有僵尸的功能,但是当选择一个项目时,相同的模糊功能会杀死我想要保留的合法数据。 GRRRRRR !!!

2)当你这样做的时候     $(&#39;#mySelector&#39;)。autocomplete({blah:blah,blah:blah}) 会发生的是ui.autocompete()类创建的一个对象,名为“uiAutocomplete”&#39;并且该对象作为数据存储在$(&#39; #mySelector&#39;)元素中。因此,要从自动完成类访问数据,选项,方法等,您只需查看     $(&#39;#mySelector&#39)。数据() 一切都在这里!

这很漂亮,因为它意味着像     $(&#39;#mySelector&#39)的数据。(&#39; uiAutocomplete&#39;) 将为您提供整个enchilada,如果您想覆盖任何自动完成功能,您可以通过调用来完成     $(&#39;#mySelector&#39;)。数据(&#39; uiAutocomplete&#39;)。myFavoriteFunction = function(){...做一些漂亮的东西..}。

您不必担心原型,子类化或其他任何问题。使用它的一个好方法是从ui-autocomplete源代码中复制确切的函数,然后将其粘贴到您的实例上,然后使用它。你不能破坏任何东西,因为你没有改变原始的源(类)代码,你只需更改实例的代码。好玩,嗯?

3)当你这样做的时候     $(&#39;#mySelector&#39;)。autocomplete({foo:function(event,ui){..在这里做东西..} 你可以用这种方式发明你想要的任何功能,然后通过这样做来调用它     this._trigger(&#39; foo&#39;,event)。

这意味着&#39;官方&#39;关闭&#39;,&#39;开放&#39;,&#39;焦点&#39;,&#39;选择&#39;等方法只是提供建议&#39; ;你可以编写自己的函数,而不需要特殊的魔法来实现它们。您的特殊职能可以成为一流的公民。就在官方旁边,没有人知道其中的区别。唯一的区别是内置&#39;函数被称为源代码,您必须手动调用函数。您可以从代码中的任何位置调用它们,因为它们可以通过它们访问     $(&#39;#mySelector&#39)的数据。(&#39; uiAutocomplete&#39)。myFunctionName()

4)此外,像&u-menu&#39;和&#39; uiAutocompetemenuItem&#39;作为数据存储在各自的对象中。在通常情况下,这些对象在首次加载页面时不存在,但您可以使用on()将事件绑定到将来创建的对象。例如,这会将mouseenter事件绑定到将来创建的所有&#39; li.spam&#39;对象,并使它们在鼠标悬停时变为红色,另外从对象的.data()字典中取一个值并将其分配给$(&#39; #mySelector&#39;)。 :

$('body').on( {
mouseenter: function() {
    $(this).children('a').css("color", "red");
    var currentItem = $(this).data('uiAutocompleteItem');
    $('#mySelector').value(currentItem.someValue);
}
}, "li.spam");

整个辣酱玉米饼馅的代码(自包含,如果评论过多则道歉):

<!DOCTYPE html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.0/jquery-ui.min.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/smoothness/jquery-ui.css" type="text/css" />
<title>fiddle</title>
<script>
(function ($) {

var quoteList = [
    { 'id': "1",
      'label': "We're here to preserve democracy.",
      'value': "We're here to preserve democracy, not practice it.",
      'description': "Capt. Ramsey to Lt. Commander Hunter",
      'title': "Gene Hackman as Capt. Ramsey, Denzel Washington as Lt. Cmdr. Hunter",
        'stub' : "Crimson Tide",
        'image': "http://2.bp.blogspot.com/_nY72TdvmuKk/S0aoHWh0LeI/AAAAAAAABjY/Yu4krTxxboM/s400/crimsontide.jpg"
    },
    {   'id': "2",
        'label': "Well, don't like [that cigar] too much.",
       'value': "Capt. Ramsey: How do you like that cigar? Hunter: It's good, sir. Capt. Ramsey: It's your first? Hunter: [coughing] Yeah. Capt. Ramsey: Well, don't like it too much. They're more expensive than drugs. ",
       'description': "Capt. Ramsey to Lt. Commander Hunter",
        'title': "Gene Hackman as Capt. Ramsey, Denzel Washington as Lt. Cmdr. Hunter",
        'stub' : "Crimson Tide",
        'image': "http://www.vimbly.com/blog/wp-content/uploads/2012/11/26-e1352860345409.jpg"
      },
    {   'id': "3",
        'label': "I expect and demand your very best.",
       'value': "I expect and demand your very best. Anything less, you should have joined the Air Force.",
       'description': "Ramsey to the crew of the Crimson Tide",
        'title': "Gene Hackman as Capt. Ramsey, Denzel Washington as Lt. Cmdr. Hunter",
        'stub' : "Crimson Tide",
        'image': "http://i2.cdnds.net/12/34/618x405/movies_tony_scott_films_8.jpg"
      },
     { 'id': "4",
        'label': "The Kirby Silver Surfer is the only true Silver Surfer.",
       'value': "Everybody knows that the Kirby Silver Surfer is the only true Silver Surfer.",
       'description': "Hunter to Petty Officer First Class Danny Rivetti (Danny Nucci)",
         'title': "Gene Hackman as Capt. Ramsey, Denzel Washington as Lt. Cmdr. Hunter",
         'stub' : "Crimson Tide",
         'image': "http://www.empireonline.com/images/features/a-z/quentin-tarantino/4.jpg"
      },
    {   'id': "5",
        'label': "I don't trust air I can't see.",
       'value': "I don't trust air I can't see.",
       'description': "Ramsey to Hunter",
        'title': "Gene Hackman as Capt. Ramsey, Denzel Washington as Lt. Cmdr. Hunter",
        'stub' : "Crimson Tide",
        'image': "http://images3.cinema.de/imedia/1853/2211853,JSg9qf_ICg9XI70_mnk+0YKnEwjDCNvEJ135zZiOOG51Em+3vDb9zfon3uv_jNxJfz3ogxTr3jHE26akqhRXcA==.jpg"
      },
    {   'id': "6",
        'label': "Mr Hunter. I've made a decision.",
       'value': "Mr Hunter. I've made a decision. I'm Captain of this boat. NOW SHUT THE FUCK UP!",
       'description': "Ramsey to Hunter",
        'title': "Gene Hackman as Capt. Ramsey, Denzel Washington as Lt. Cmdr. Hunter",
        'stub' : "Crimson Tide",
        'image': "http://images.static-bluray.com/reviews/271_1.jpg"
      },
    {   'id': "7",
        'label': "Mr. Vossler, this is Captain Kirk!",
       'value': "Mr. Vossler, this is Captain Kirk! I need warp speed on that communications unit!",
       'description': "Hunter to Petty Officer Third Class Russell Vossler (Lillo Brancato)",
        'title': "Gene Hackman as Capt. Ramsey, Denzel Washington as Lt. Cmdr. Hunter",
        'stub' : "Crimson Tide",
        'image': "http://www.livedash.com/thumb_v5/20091130/crimson%20tide-2009-11-30-0/2_crimson%20tide-2009-11-30-0.jpg"
      },
    {   'id': "8",
        'label': "I will marry a round American woman and raise rabbits.",
       'value': "I will live in Montana. And I will marry a round American woman and raise rabbits, and she will cook them for me. And I will have a pickup truck... maybe even a recreational vehicle. And drive from state to state. Do they let you do that? ",
       'description': "Capt. Vasili Borodin (Sam Neill) to Ramius",
        'title': "Sean Connery as Capt. Ramius, Alec Baldwin as Jack Ryan",
        'stub' : "Crimson Tide",
        'image': "http://1.bp.blogspot.com/-08wMMkx53XQ/TrNoK0ykLzI/AAAAAAAAkK0/p5Q_F6EOrvI/s360/Crimson-Tide.jpg"
      },
    {   'id': "9",
        'label': "We will lay off their largest city, and listen to their rock and roll!",
       'value': "We will pass through the American patrols, past their sonar nets, and lay off their largest city, and listen to their rock and roll... while we conduct missile drills.",
       'description': "Ramius to the crew of the The Hunt for Red October",
        'title': "Sean Connery as Capt. Ramius, Alec Baldwin as Jack Ryan",
        'stub' : "The Hunt for Red October",
        'image': "http://libcom.org/files/images/library/alec_baldwin1%5B1%5D.jpg"
      },
    {   'id': "10",
        'label': "You're afraid. Well, you should be. Personally, I'd give us one chance in three. More tea anyone?",
       'value': "You're afraid of our fleet. Well, you should be. Personally, I'd give us one chance in three. More tea anyone? ",
       'description': "Ramius to the officers of the The Hunt for Red October",
        'title': "Sean Connery as Capt. Ramius, Alec Baldwin as Jack Ryan",
        'stub' : "The Hunt for Red October",
        'image': "http://i77.photobucket.com/albums/j60/bluinkalchemist/hunt-for-red-october_480_poster.jpg"

      },
    {   'id': "11",
        'label': "Hey, Ryan, be careful what you shoot at. Most things in here don't react too well to bullets.",
       'value': "Hey, Ryan, be careful what you shoot at. Most things in here don't react too well to bullets.",
       'description': "Ramius to Ryan",
        'title': "Sean Connery as Capt. Ramius, Alec Baldwin as Jack Ryan",
        'stub' : "The Hunt for Red October",
        'image': "http://wodumedia.com/wp-content/uploads/2012/10/Sean-Connery-and-Alec-Baldwin-in-Paramounts-The-Hunt-For-Red-October-1990-0.jpg"

      },
    {   'id': "12",
        'label': "When he reached the New World, Cortez burned his ships. As a result his men were well motivated.",
       'value': "When he reached the New World, Cortez burned his ships. As a result his men were well motivated.",
       'description': "Remius to the officers of the The Hunt for Red October",
        'title': "Sean Connery as Capt. Ramius, Alec Baldwin as Jack Ryan",
        'stub' : "The Hunt for Red October",
        'image': "http://content.internetvideoarchive.com/content/photos/070/002974_25.jpg"

      },
    {   'id': "13",
        'label': "Russians don't take a dump, son, without a plan.",
       'value': "'The average Ruskie, son, don't take a dump without a plan.' Wait a minute. We don't have to figure out how to get the crew off the sub. He's already done that, he would have had to. All we gotta do is figure out what he's gonna do. So how's he gonna get the crew of the sub. ",
       'description': "Ryan reliving a comment by Admiral Josh Painter (Fred Thompson)",
        'title': "Sean Connery as Capt. Ramius, Alec Baldwin as Jack Ryan",
        'stub' : "The Hunt for Red October",
        'image': "http://toddmpost.files.wordpress.com/2010/12/admiralpainter.jpg?w=640"

      },
    {   'id': "14",
        'label': "At that speed, they could run right over my daughter's stereo and not hear it.",
       'value': "They're pinging away with their active sonar like they're looking for something, but nobody's listening... they're moving at almost forty knots. At that speed, they could run right over my daughter's stereo and not hear it.",
       'description': "Capt. Davenport (Daniel Davis) to Ryan",
        'title': "Sean Connery as Capt. Ramius, Alec Baldwin as Jack Ryan",
        'stub' : "The Hunt for Red October",
        'image': "http://libcom.org/files/images/library/alec_baldwin1%5B1%5D.jpg"

      },
    {   'id': "15",
        'label': "I would like to have seen Montana.",
       'value': "I would like to have seen Montana.",
       'description': "Capt. Vasili Borodin (Sam Neill) to Capt. Ramius",
        'title': "Sean Connery as Capt. Ramius, Alec Baldwin as Jack Ryan",
        'stub' : "The Hunt for Red October",
        'image': "http://img.geocaching.com/track/display/ad4047d5-a1f9-4a39-86c9-8a7a0873f1ef.jpg"

      },
    {   'id': "16",
        'label': "Next time, Jack, write a goddamn memo.",
       'value': "Next time, Jack, write a goddamn memo.",
       'description': "Ryan (talking to himself)",
        'title': "Sean Connery as Capt. Ramius, Alec Baldwin as Jack Ryan",
        'stub' : "The Hunt for Red October",
        'image': "http://www.wearysloth.com/Gallery/ActorsB/860-9042.gif"

      },
    {   'id': "17",
        'label': "Give me a ping, Vasili. One ping only, please.",
       'value': "Re-verify our range to target... one ping only. Give me a ping, Vasili. One ping only, please.",
       'description': "Ramius to Capt. Vasili Borodin (Sam Neill)",
        'title': "Sean Connery as Capt. Ramius, Alec Baldwin as Jack Ryan",
        'stub' : "The Hunt for Red October",
        'image': "http://25.media.tumblr.com/tumblr_ma1prrCDn81qkcj94o1_1280.jpg"

      },
    {   'id': "18",
        'label': "Come up right behind his propellor and he'll be deaf as a post!",
       'value': "Not if we stay in his baffles, Seaman Beaumont. Not if we stay in his baffles. Come up right behind his propellor and he'll be deaf as a post!",
       'description': "Seaman 'Jonesy' Jones (Courtney Vance) to Seaman Beaumont (Ned Vaughn)",
        'title': "Sean Connery as Capt. Ramius, Alec Baldwin as Jack Ryan",
        'stub' : "The Hunt for Red October",
        'image': "http://cdn3.hark.com/images/000/375/672/375672/original.jpg"

      },
    {   'id': "19",
        'label': "Andrei, you've lost another submarine?",
       'value': "One of our submarines, an Alfa, was last reported in the area of the Grand Banks. We have not heard from her for some time..... Andrei, you've lost another submarine?",
       'description': "Dr. Jeffrey Pelt (Richard Jordan) to Russian Ambassador Andrei Lysenko (Joss Ackland)",
        'title': "Sean Connery as Capt. Ramius, Alec Baldwin as Jack Ryan",
        'stub' : "The Hunt for Red October",
        'image': "http://www.wearysloth.com/Gallery/ActorsJ/8969-9042.gif"
      }
 ];

$(document).ready (function () {

    $( "#id_quote" ).autocomplete({
        minLength: 2,
        delay: 2,
        source: quoteList,
        open: function(event, ui) {
            // defines the character of the ui-menu
            $(".ui-autocomplete")
            .css("width", "300px")
            .css("max-height", "200px")
            .css("overflow-y", "scroll")
        },
        focus: function( event, ui ) {
            // This causes ancillary fields to populate whenever a menu choice is hovered
            // also works if menu choices are navigated with keyboard up and down arrows
            $( "#id_stub" ).val( ui.item.stub );
            $( "#id_title" ).val( ui.item.title );
            $( "#id_description" ).val( ui.item.description );
            $( "#id_dialog" ).val( ui.item.value );
            $( '#id_image').html("<img style='width:100%; height:100%;' src='" + ui.item.image + "' />");
                // Ensures that when mouse leaves the manu, that the ancillary fields are emptied
                // This is a 'one ping only' event, because 'mouseout' is triggered by the closing of the
                // menu when a true choice is made (either by mouse click or return key).
                // Making this 'one ping only' ensures that the ancillary fields don't empty
                // when the menu closes after a valid selection is made.
                // Of course, if there is a new focus, the 'one ping only' rule must be re-established,
                // so it is put here, in the focus callback:
            $('li.one-ping-only').one ("mouseleave", function() {
                $( "#id_stub" ).val("");
                $( "#id_title" ).val("");
                $( "#id_description" ).val("");
                $( "#id_dialog" ).val("");
                $( '#id_image').empty();
            });
        },
        select: function( event, ui ) {
            // Takes off the 'one ping only' mouse event binding,
            // otherwise it would cause the ancillary fields to empty
            // due to the 'mouseout' that happens automatically when
            // the menu closes.
            // In some cases, the mouseout binding has already been removed, but
            // in other cases not (by a true mouseout event).  This is a safe
            // way to make sure before a selection event fills the fields.
            $('li.one-ping-only').off("mouseleave");
            $( "#id_stub" ).val( ui.item.stub );
            $( "#id_title" ).val( ui.item.title );
            $( "#id_description" ).val( ui.item.description );
            $( "#id_dialog" ).val( ui.item.value );
            $( '#id_image').html("<img style='width:100%; height:100%;' src='" + ui.item.image + "' />");
            $( "#id_quote" ).val( ui.item.value )
                // In general, we want to make sure that if the user goes back and types
                // again or backspaces in the autocomplete input, AFTER making a selection, then the
                // ancillary fields will blank, to avoid zombie data persistence.
                // Unfortunately, making a selection with the return key (vs. a mouse click)
                // sends (or propagates?) a return key event to the original input field, AFTER the select
                // event has been called.  Thus, though a valid select event populates the fields (by the
                // actions immediately above), the ancillary data is them immediately erased
                // by this key event that arrives a split second later.
                // To counter this, we make an exception so that in the event that the first key event arriving
                // after a select event happens to be a return key, (the selection was made with the keyboard)
                // then that single key event is exempted from blanking the field.
            .one ("keypress", function (e) {
                if (e.keyCode !== 13) {
                    $( "#id_stub" ).val("");
                    $( "#id_title" ).val("");
                    $( "#id_description" ).val("");
                    $( "#id_dialog" ).val("");
                    $( '#id_image').empty();
                }
                else {
                    // The 'one ping only' event above is REMOVED if any key event takes place, even if it was
                    // as 'disqualified' return key event.   So,  even though nothing happened visibly,
                    // we need to re-establish our 'one ping only' protection from 'real editing' key event.
                    $( "#id_quote" ).one ("keypress", function (e) {
                        if (e.keyCode !== 13) {
                            $( "#id_stub" ).val("");
                            $( "#id_title" ).val("");
                            $( "#id_description" ).val("");
                            $( "#id_dialog" ).val("");
                            $( '#id_image').empty();
                        }
                    })
                }
            });
        }
    }).data("uiAutocomplete")._renderItem = function( ul, item ) {
        // The uiAutocomplete object is stored as part data in the input field it is attached to.
        // When we call .data("uiAutocomplete") here, it relates back to data attribute of the $( "#id_quote" ) that the
        // autocomplete widget function was attached to.  It's helpful to realize that the uiAutocomplete object is part of the
        // $( "#id_quote" ).data() and can be called at any time, not just here right after autocomplete is called.
        // This can be confusing, but just remember that once you do $( "#id_quote" ).autocomplete({blah blah}), then forever
        // .data() attribute of the $( "#id_quote" ) will contain a 'uiAutocomplete' object, the properties of which are the
        // properties defined in the jQuery-ui class autocomplete, as instantiated by you.
        // Anyway, we want to override one of the autocomplete methods, specifically the _renderItem method
        // that makes the items in the menu.
        // Here, we specify the nature of the presentation, giving it first the traditional label, and also another line
        // that in this case is item.description.
        // In addition, we perform a regular expression match on the label, and highlight the letters/words
        // that match the search term we have typed into our search input.
        var regxpmatch = new RegExp(this.term, "ig");
        // Note the 'g' in 'ig' means global to catch any place the letters match, otherwise the default is to match only the first
        // instance in any item.label.
        // Also note the 'i' in 'ig' makes the match case insensitive.
        var formatted_quote = item.label.replace(regxpmatch,"<span style='font-weight:bold;color: red;'>" + this.term + "</span>");
        return $( "<li class='one-ping-only'></li>" )
        // the 'one-ping-only' class is the hook for our callbacks that erase ancillary fields when a user edits the original
        // input after making a selection, and also is used for another callback that erases ancillary fields if the menu loses
        // focus by moving the mouse out of the menu, or alternatively using the up or down key on the keyboard to leave
        // the menu.
        .append( "<a><div class='subquote'>" + formatted_quote + "</div><div class='subtitle'>" + item.description + "</div></a><hr>" )
        // makes the menu item have two lines, and puts a horizontal line between each item pair.
        .appendTo( ul );
    };
    $( "#id_quote" ).data( "uiAutocomplete" )
    ._move = function( direction, event ) {
        // here we are using a similar logic to override the _move method, ensuring that if the user exits the menu
        // using the keyboard, the ancillary fields will clear, just as they do with the 'one ping only' mouseout function
        // described above.
        if ( !this.menu.element.is( ":visible" ) ) {
            this.search( null, event );
            return;
        }
        if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
                this.menu.isLastItem() && /^next/.test( direction ) ) {
            this._value( this.term );
            $( "#id_stub" ).val("");
            $( "#id_title" ).val("");
            $( "#id_description" ).val("");
            $( "#id_dialog" ).val("");
            return;
        }
        this.menu[ direction ]( event );
    };
});

})(jQuery);
</script>
<style type="text/css">
    div.subquote {font-size: 11px;}
    div.subtitle {font-size: 9px; color: blue;}
    #id_quote {width: 250px; height:100px;}
    #id_stub {width: 250px;}
#id_title, #id_description {width: 250px;}
#id_dialog {width: 250px; min-height: 100px;}
</style>
</head>
<body>
<form action="#" method='POST'>
<div style="float:left; width: 300px;">
    <h4>Search submarine movie quotes...</h4>
    <h4>...or simply write in your own!</h4>
    <div>
        <textarea name="quote"  type="text" id="id_quote" placeholder="Start typing here...." ></textarea>
    </div>

</div>
<div style="float:left; margin-left: 50px;">
    <div style="margin: 5px 0 5px 10px;">
        <input name="stub"  type="text" id="id_stub" />
    </div>
    <div style="margin: 5px 0 5px 10px;">
        <textarea name="title"  type="text" id="id_title" ></textarea>
    </div>
    <div style="margin: 5px 0 5px 10px;">
        <textarea name="description"  type="text" id="id_description"></textarea>
    </div>
    <div style="margin: 5px 0 5px 10px;">
        <textarea name="dialog"  type="text" id="id_dialog"></textarea>
    </div>
    <button type="submit" id="id_button">Submit your Favorite!</button>
    <div name="image" id="id_image" style="width: 250px; height:250px;">
    </div>
</div>
</form>
</body>

答案 1 :(得分:2)

在您的具体示例中,您只需在文本输入上收听“keyup”事件即可。每次触发事件时,您都可以检查.ui-autocomplete元素并检查具有“ui-state-active”类的列表项。如果这是0,那么你就知道什么都没有被选中。

http://jsfiddle.net/UVauY/3/

$("#id_main_course").on('keyup',function(){
     if($(".ui-autocomplete a.ui-state-active").length === 0){
         clearall();
     }
});

这适用于您所描述的内容,但存在一些问题。如果用户将鼠标悬停在列表中的某个项目上,则不会清除输入,然后将其悬停在该项目之外。这导致在大约1秒延迟之后取消选择项目。如果不是因为这个延迟,你可能会听到该项目上的mouseout事件并使用上面相同的逻辑。但是,就像你说的那样,除了自己修改jquery UI源以添加该功能之外,还没有一个很好的解决方案。

答案 2 :(得分:2)

您可以尝试覆盖_renderItem函数,一旦构建了列表项,使用“unhover”函数为其添加适当的悬停事件。

可能会工作......

More on renderItem