我正在创建我的第一个jQuery插件,并在下面有一个有点工作的例子(参见http://tapmeister.com/test/selector.html)和脚本。我一直在努力将元素定位好几天。
所需的外观和功能从显示文本右侧的一些文本和可选向下箭头开始。单击后,文本/箭头将替换为选项列表,其中突出显示当前所选选项并位于原始文本的相同位置。单击选项使其成为当前选定的选项,并启动用户定义的回调,并单击任何其他空格将关闭对话框。
插件替换原始的select元素,我希望保留它是内联还是块。但是,在使它们内联时,位置:绝对<ul class="selectIt-list">
弹出窗口不会出现在其关联文本<span class="selectIt-text">
上方。由于span文本和ul popup都在位置:relative <div class="selectIt">
,为什么它位于最左边?
作为旁注,我这样做的一个主要原因是要了解如何构建插件的一致模式。我强烈建立http://docs.jquery.com/Plugins/Authoring的方法(任何理由我都不应该这样做)。我希望有人可以查看它,确认我是否正确解释如何构建插件,并提供任何建议。我也不确定我是否真的得到了整个名称空间。也许我应该把它作为一个单独的问题发布?但我不知道是否要求代码批评是合适的。
谢谢!
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
<title>Testing</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<style type="text/css">
/* CSS associated with plugin */
div.selectIt {
position:relative;
}
span.selectIt-text {
color: #2C46B7;
cursor: pointer;
font-family: Verdana;
font-size: 10px;
display:inline;
}
span.selectIt-text,
ul.selectIt-list {
padding: 7px 3px 5px;
}
ul.selectIt-list {
display:none;
margin:0px;
position: absolute;
background-color: #FFFFFF;
border: 1px solid #B3B4A7;
z-index: 50;
box-shadow: 3px 1px 6px #505050;
}
ul.selectIt-list li {
background-color: #FFFFFF;
color: #393926;
list-style-type: none;
font-family: Verdana;
font-size: 10px;
margin-bottom: 2px;
padding-left: 2px;
padding-right: 2px;
}
ul.selectIt-list li.selectIt-hover {
background-color: #DFDED8;
color: #393926;
}
ul.selectIt-list li.selectIt-selected {
background-color: #737060;
color: #FFFFFF;
cursor: default;
}
/* CSS Not associated with plugin */
ul.myList > li {
list-style-type: none;
display:inline;
}
#horizontalList select.mySelect {
display:inline;
}
#verticalList select.mySelect {
display:block;
}
span.label {
color: rgb(57, 57, 38);
font-family: Verdana;
font-size: 10px;
font-weight: bold;
}
span.selectIt-text {
background-image: url("dropdown_arrow_blue.gif");
background-position:right center;
background-repeat: no-repeat;
padding-right: 10px; /*Override padding-right to allow for image*/
}
</style>
<script>
/*
* jQuery SelectIT
* Copyright 2012 Michael Reed
* Dual licensed under the MIT and GPL licenses.
*
*/
(function( $ ){
var methods = {
init : function( options ) {
//console.log('init');
// Create some defaults, extending them with any options that were provided
var settings = $.extend({
'class' : null, //Applies custom class so user may override
'extraWidth' : 0, //Extra space to add to width to allow for user image css
'click' : function(){} //Some user defined code.
}, options || {}); //Just in case user doesn't provide options
//Apply events that should only happen once (unlike what is done by http://docs.jquery.com/Plugins/Authoring#Events. Why did they do it that way?)
$(document).on('click.selectIt',methods.close);
return this.each(function(){
var $t = $(this),
data = $t.data('selectIt');
//Replace element
var list = $('<ul/>', {'class': "selectIt-list" }),
length,
max=0;
$t.find('option').each(function(i){
var $this=$(this),
text=$this.text(),
length = parseInt($this.css('width'));
max = length > max ? length : max;
list.append( $('<li/>', {text: text}))
});
max=max+settings.extraWidth;
list.css('width',max+'px');
var selectIt = $('<div/>', {class:"selectIt"+((settings.class)?' '+settings.class:'')}) //Didn't work to display same as original element: display:$t.css('display')
.append($('<span/>', {class:'selectIt-text',text:$t.find(":selected").text()}))
.append(list)
.css({display:$t.css('display')}); //Set to same as original element
//Apply events
selectIt.on('click.selectIt','span.selectIt-text',methods.open);
selectIt.on('mouseenter.selectIt','ul.selectIt-list li',methods.mouseenter);
selectIt.on('mouseleave.selectIt','ul.selectIt-list li',methods.mouseleave);
selectIt.on('click.selectIt','ul.selectIt-list li',methods.click);
// If the plugin hasn't been initialized yet. Why?
if ( ! data ) {
// Do more setup stuff here
$t.data('selectIt', {
target : $t, //Not really sure where this will be used
selectIt : selectIt, //Will be used when removing in destroy method
settings: settings //Save here so other methods have access
});
}
$t.hide().after(selectIt);
});
},
destroy : function(e) {
//console.log('destroy');
return this.each(function(){
var $t = $(this);
$t.off('.selectIt'); //Removes any events in selectIt namespace
$t.data('selectIt').selectIt.remove(); //Removes element from page
$t.removeData('selectIt'); //Removes data in selectIt namespace
//Should the original element be made visible?
})
},
open : function(e) {
//console.log('open');
methods.close();
var $t=$(this),
$p=$t.parent(),
index=$p.prev().prop("selectedIndex"),
list=$p.find('ul.selectIt-list').show();
list.find('li.selectIt-selected').removeClass('selectIt-selected');
list.find('li').eq(index).addClass('selectIt-selected');
var top = 0 - list.find('li').eq(index).position().top;
list.css({top: top});
e.stopPropagation(); //Don't trigger documents click
},
//If this is all I am doing, can change to just using CSS psudo class.
mouseenter : function(e) {
$(this).addClass('selectIt-hover');
},
mouseleave : function(e) {
$(this).removeClass('selectIt-hover');
},
click : function(e) {
//console.log('click');
var $t=$(this);
if(!$t.hasClass('selectIt-selected'))
{
var $p=$t.parent(),
$pp=$p.parent(),
select=$pp.prev(),
index=$t.index(),
option=select.find('option').eq(index),
value=(value=option.val())?value:option.text();
select.val(value).prop('selectedIndex',index);
$pp.find('span.selectIt-text').text($t.text());
select.data('selectIt').settings.click.call(this,value);
}
},
close : function(e) {
//console.log('close');
$('div.selectIt').find('ul.selectIt-list').hide().parent();//.find('span.selectIt-text').show();
},
update : function(content) {alert('When will this type of method be used?');}
};
$.fn.selectIt = 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 + ' does not exist on jQuery.selectIt' );
}
};
})( jQuery );
$(function(){
$('select.mySelect').selectIt({
//'class' : 'whatever',
'extraWidth' : 0,
'click':function(value){
switch(value)
{
case 'first':console.log('Do something first');break;
case 'second':console.log('Do something second');break;
case 'third':console.log('Do something third');break;
default: console.log('Do something default');
}
}
});
$('#horizontalList button.destroy').click(function(){
$('#horizontalList select.mySelect').selectIt('destroy');
});
$('#verticalList button.destroy').click(function(){
$('#verticalList select.mySelect').selectIt('destroy');
});
});
</script>
</head>
<body>
<div id="horizontalList">
<h1>Horizontal List</h1>
<ul class="myList">
<li>
<span class="label">Label</span>
<select class="mySelect">
<option value="first">First</option>
<option value="second" selected="selected">Second</option>
<option>Third</option>
</select>
</li>
<li>
<span class="label">Some Label</span>
<select class="mySelect">
<option value="first">First</option>
<option value="second" selected="selected">Second</option>
<option value="third">Third</option>
</select>
</li>
<li>
<span class="label">Some Label</span>
<select class="mySelect">
<option value="">First</option>
<option value="second">Second</option>
<option value="third">Third</option>
</select>
</li>
</ul>
<button class="destroy">Destroy</button>
</div>
<div id="verticalList">
<h1>Vertical List</h1>
<ul class="myList">
<li>
<span class="label">Label</span>
<select class="mySelect">
<option value="first">First</option>
<option value="second" selected="selected">Second</option>
<option>Third</option>
</select>
</li>
<li>
<span class="label">Some Label</span>
<select class="mySelect">
<option value="first">First</option>
<option value="second" selected="selected">Second</option>
<option value="third">Third</option>
</select>
</li>
<li>
<span class="label">Some Label</span>
<select class="mySelect">
<option value="">First</option>
<option value="second">Second</option>
<option value="third">Third</option>
</select>
</li>
</ul>
<button class="destroy">Destroy</button>
</div>
</body>
</html>
答案 0 :(得分:1)
为了定位您所描述的内容,我强烈建议您使用 jQuery的“my at of”定位。这是一个巨大的头痛救星!
http://docs.jquery.com/UI/API/1.8/Position
应用于您的示例,它看起来像:
//PLACE INSIDE YOUR EVENT HANDLER
$(".selectIt-list").position({
my: "bottom center",
at: "top center",
of: ".selectIt-text",
});
答案 1 :(得分:1)
JQuery中有一行[第173行]:
list.css({top: top});
在它下面插入这一行:
list.css({left: $(this).position().left});