I'm trying to create a drop-down menu in a plugin manner. I'm familiar with scripting myself to solutions but I've never created a plugin before so I'm trying to learn how to do this, and therefore raising my level as a jQuery developer.
I'm trying to create basic drop down functionality. You have a link. You click it, a drop down of links appear. You click outside of the link (the document) the menu of links goes away.
I'm having trouble on the go away part. I tried to bind it to document.click but of course that shows the menu and then hides it, as there is nothing making sure it has to be shown first. How do I do this?
How do I make it so that the menu only hides after it is shown if you click outside of it?
application.js
jQuery(document).ready(function($){
$("ul.drop-down").sillyDropDown();
// failed attempt (shows and hides). Probably should go in plugin anyway.
// $(document).click(function(){
// $("ul.drop-down").sillyDropDown('hide');
// });
});
silly_drop_down.js
(function($){
var methods = {
init : function(options){
return this.each(function(){
var $this = $(this);
var selector = $(this).children()[0];
var link = $(selector);
link.bind('click.silly', methods.show);
});
},
show : function() {
var $this = $(this);
var menu = $this.siblings("ul");
menu.slideDown("slow");
},
hide : function(){
var $this = $(this);
var menu = $this.children("ul");
menu.slideUp("slow");
}
};
$.fn.sillyDropDown = function(method){
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 );
} else {
$.error( 'Method ' + method 开发者_JAVA百科+ ' does not exist on jQuery.sillyDropDown' );
}
};
})(jQuery);
the html if it matters
<ul id="project-settings" class="drop-down">
<li>
<a href="#">
Settings
<img src="/images/iconic/white/cog_alt_16x16.png" class="stale">
<img src="/images/iconic/orange/cog_alt_16x16.png" class="hover">
</a>
</li>
<ul style="display: none;">
<div class="pointer"></div>
<li class="first">
<a href="#">Settings...</a>
</li>
<li>
<a href="#">Collaborators...</a>
</li>
<li>
<a href="#">Comments...</a>
</li>
<hr>
<li>
<a href="#">Delete Project</a>
</li>
</ul>
</ul>
edit (I realized I asked similar question in past). I did the following in application.js
$("ul.drop-down").sillyDropDown();
$(document).bind("click.silly", function(e){
var nav = $("ul.drop-down");
var target = $(e.target);
if (target.closest("ul.drop-down").length < 1){
nav.sillyDropDown('hide');
return;
}
});
This does the job. However it doesn't seem elegant to do it in application.js - How would I handle this inside the plugin?
Note: I'll probably have multiple instances of ul.drop-down - Am I missing something in my implementation to take care of this? So far only have one in my tests.
Also, how would I make it so that if I click a link inside the drop down I can force the menu to hide (this would be a modal popup for example).
added this for now in application.js
$("ul.drop-down ul li a").click(function(e){
$("ul.drop-down ul").hide();
return;
});
Feels again, very unelegant and should probably be put somewhere else. Educate me please!
I would bind the menu close action to $(window).click
, then in the dropdown's own click event add e.stopPropogation()
. That prevents the click from bubbling further up the DOM tree to the window element.
Or just use the menu's blur
event. Think that'd work even on non-input elements.
Here's an example: http://jsfiddle.net/5tgGq/1/. The important part is in init
:
init: function(options) {
return this.each(function() {
var self = this;
$(this).click(methods.show);
$(document).click(function(e) {
if ($(self).has(e.target).length === 0) {
methods.hide.apply(self);
}
});
});
},
Hope that helps. I'm pretty sure you should be ok with multiple elements as well, since you're only using the show
and hide
methods for elements you already each
ed.
EDIT: here's an example with two lists: http://jsfiddle.net/5tgGq/3/
精彩评论