我正在创建我的第一个 jQuery 插件,并且有一个工作示例(参见http://tapmeister.com/test/selector.html)和下面的脚本。几天来,我一直在努力定位一个元素。
所需的外观和功能从显示一些文本和文本右侧的可选向下箭头开始。单击后,文本/箭头将替换为选项列表,当前选定的选项突出显示并位于原始文本的相同位置。单击一个选项使其成为当前选定的选项,并启动用户定义的回调,单击任何其他空间将关闭对话框。
该插件替换了原始的选择元素,我希望保留它是内联的还是块状的。但是,当使它们内联时, position:absolute<ul class="selectIt-list">
弹出窗口不会出现在其关联的 text 上方<span class="selectIt-text">
。由于 span text 和 ul popup 都在 position: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>