Posted by Mr.Think on 02/28/2012
好像很久没有更新过博客了,哈~
发布一款最近写的jQuery小插件,用于统一下拉表样式并实现select样式高度自定义。select样式如同input[type=file]一样,各系统平台各浏览器显示的都不一样,特别是ie~一切影响美感的东西较真的UI设计狮们是不会妥协的。兵来将挡,水来土淹,为了保持最近一个公司项目中部分下拉列表的美观统一,用一种变通的方式为select穿上一套标准的新衣:不论平台不论浏览器样式统一、样式高度自定义、不破坏select原有结构与功能(这意味着后端程序仍可像调用普通select那样取值)。

原理无须多讲,在需要改变样式的select后插入一个div容器,同时隐藏掉select。然后把select的相关信息(optgroup/option/value/selected等)取出来用dl展现,如此一来,改变div容器中元素样式即可。记得前年写过一个用input[type=hidden]存值,用dl模拟下拉列表的插件。两者原理差不多,只是本文中的可能更人性化,使用起来更方便些。
jQuery代码:点此查看样列
;(function($){
/*
* 统一select样式并实现样式高度自定义的jQuery插件@Mr.Think(http://mrthink.net/)
*/
$.fn.iSimulateSelect=function(iSet){
iSet=$.extend({
selectBoxCls:'i_selectbox', //string类型,外围class名
curSCls:'i_currentselected',//string类型,默认显示class名
optionCls:'i_selectoption',//string类型,下拉列表class名
selectedCls:'selected',//string类型,当前选中class名
width:222,//number类型,模拟select的宽度
height:300,//number类型,模拟select的最大高度
zindex:20//层级顺序
},iSet||{});
this.hide();
return this.each(function(){
var self=this;
var thisCurVal,thisSelect,cIndex=0;
//计算模拟select宽度
if(iSet.width==0){
iSet.width=$(self).width();
}
var html='<div class="'+iSet.selectBoxCls+'" style="z-index:'+iSet.zindex+'"><div class="'+iSet.curSCls+'" style="width:'+iSet.width+'px">'+$(self).find('option:selected').text()+'</div><dl class="'+iSet.optionCls+'" style="display:none;width:'+iSet.width+'px">';
//判断select中是否有optgroup
//用dt替代optgroup,用dd替代option
if($(self).find('optgroup').size()>0){
$(this).find('optgroup').each(function(){
html+='<dt>'+$(this).attr('label')+'</dt>';
$(this).find('option').each(function(){
if($(this).is(':selected')){
html+='<dd class="'+iSet.selectedCls+'">'+$(this).text()+'</dd>';
}else{
html+='<dd>'+$(this).text()+'</dd>';
}
});
});
}else{
$(this).find('option').each(function(){
if($(this).is(':selected')){
html+='<dd class="'+iSet.selectedCls+'">'+$(this).text()+'</dd>';
}else{
html+='<dd>'+$(this).text()+'</dd>';
}
});
}
//将模拟dl插入到select后面
$(self).after(html);
//当前模拟select外围box元素
thisBox=$(self).next('.'+iSet.selectBoxCls);
//当前模拟select初始值元素
thisCurVal=thisBox.find('.'+iSet.curSCls);
//当前模拟select列表
thisSelect=thisBox.find('.'+iSet.optionCls);
/*
若同页面还有其他原生select,请前往https://github.com/brandonaaron/bgiframe下载bgiframe,同时在此处调用thisSelect.bgiframe()
*/
//thisSelect.bgiframe();
//弹出模拟下拉列表
thisCurVal.click(function(){
$('.'+iSet.optionCls).hide();
$('.'+iSet.selectBoxCls).css('zIndex',iSet.zindex);
$(self).next('.'+iSet.selectBoxCls).css('zIndex',iSet.zindex+1);
thisSelect.show();
});
//若模拟select高度超出限定高度,则自动overflow-y:auto
if(thisSelect.height()>iSet.height){
thisSelect.height(iSet.height);
}
//模拟列表点击事件-赋值-改变y坐标位置-...
thisSelect.find('dd').click(function(){
$(this).addClass(iSet.selectedCls).siblings().removeClass(iSet.selectedCls);
cIndex=thisSelect.find('dd').index(this);
thisCurVal.text($(this).text());
$(self).find('option').eq(cIndex).attr('selected','selected');
$('.'+iSet.selectBoxCls).css('zIndex',iSet.zindex);
thisSelect.hide();
});
//非模拟列表处点击隐藏模拟列表
//$(document)点击事件不兼容部分移动设备
$('html,body').click(function(e){
if(e.target.className.indexOf(iSet.curSCls)==-1){
thisSelect.hide();
$('.'+iSet.selectBoxCls).css('zIndex',iSet.zindex);
}
});
//取消模块列表处取消默认事件
thisSelect.click(function(e){
e.stopPropagation();
});
});
}
})(jQuery);
如何调用?
1、在页面中引入上面的插件代码;
2、$(select).iSimulateSelect({…});
3、相关参数及功能,请参考插件中的注释说明。
若在ie6下,同页面中有未调用插件元素,为避免被原生select遮盖,请下载bgiframe插件,并在代码中关于bgiframe调用的公位置取消注释。另外,在调用插件的select后面插入的是一个相对定位元素,如果select前后还有其他行内元素,尽量使用float定位,或者给select外围加一个容器再进行绝对定位。
jQuery
Posted by Mr.Think on 12/09/2011
大多电子商务网站购物车页面,都有通过点击来增减商品数量的功能,特地根据常规功能写了一个jQuery插件。

实现的功能:
1、可通过点击增加或减小定义的input值;
2、可手动输入input值,且支持键盘控制:上右为加,下左为减;
3、可设定表单的最大最小值,并对input值进行了非负整数判断;
4、定义了回调函数,输出表单最后的input值和所改变input的索引值。也可在插件中稍稍修改一下,把想返回的值传到一个hidden input中;
点此查看样列
jQuery代码:
$.fn.iVaryVal=function(iSet,CallBack){
/*
* Minus:点击元素--减小
* Add:点击元素--增加
* Input:表单元素
* Min:表单的最小值,非负整数
* Max:表单的最大值,正整数
*/
iSet=$.extend({Minus:$('.J_minus'),Add:$('.J_add'),Input:$('.J_input'),Min:0,Max:20},iSet);
var C=null,O=null;
//插件返回值
var $CB={};
//增加
iSet.Add.each(function(i){
$(this).click(function(){
O=parseInt(iSet.Input.eq(i).val());
(O+1<=iSet.Max) || (iSet.Max==null) ? iSet.Input.eq(i).val(O+1) : iSet.Input.eq(i).val(iSet.Max);
//输出当前改变后的值
$CB.val=iSet.Input.eq(i).val();
$CB.index=i;
//回调函数
if (typeof CallBack == 'function') {
CallBack($CB.val,$CB.index);
}
});
});
//减少
iSet.Minus.each(function(i){
$(this).click(function(){
O=parseInt(iSet.Input.eq(i).val());
O-1<iSet.Min ? iSet.Input.eq(i).val(iSet.Min) : iSet.Input.eq(i).val(O-1);
$CB.val=iSet.Input.eq(i).val();
$CB.index=i;
//回调函数
if (typeof CallBack == 'function') {
CallBack($CB.val,$CB.index);
}
});
});
//手动
iSet.Input.bind({
'click':function(){
O=parseInt($(this).val());
$(this).select();
},
'keyup':function(e){
if($(this).val()!=''){
C=parseInt($(this).val());
//非负整数判断
if(/^[1-9]\d*|0$/.test(C)){
$(this).val(C);
O=C;
}else{
$(this).val(O);
}
}
//键盘控制:上右--加,下左--减
if(e.keyCode==38 || e.keyCode==39){
iSet.Add.eq(iSet.Input.index(this)).click();
}
if(e.keyCode==37 || e.keyCode==40){
iSet.Minus.eq(iSet.Input.index(this)).click();
}
//输出当前改变后的值
$CB.val=$(this).val();
$CB.index=iSet.Input.index(this);
//回调函数
if (typeof CallBack == 'function') {
CallBack($CB.val,$CB.index);
}
},
'blur':function(){
$(this).trigger('keyup');
if($(this).val()==''){
$(this).val(O);
}
//判断输入值是否超出最大最小值
if(iSet.Max){
if(O>iSet.Max){
$(this).val(iSet.Max);
}
}
if(O<iSet.Min){
$(this).val(iSet.Min);
}
//输出当前改变后的值
$CB.val=$(this).val();
$CB.index=iSet.Input.index(this);
//回调函数
if (typeof CallBack == 'function') {
CallBack($CB.val,$CB.index);
}
}
});
}
若有bug,请以评论形式及时反馈~
jQuery
Posted by Mr.Think on 11/05/2011
油翁酌油沥钱,自钱孔入而钱不湿。因曰:“我亦无他, 唯手熟尔”。
好久没有好好的写过代码了,博客也有好几个月没有更新。忙于工作,忙于人身大事,忙于琐碎。最近相对清闲,正好一个做后端的朋友求助于我,帮他写一个新蛋网首页多屏自动切换效果。顺便分享之。

思路很简单,详见代码。本来是想封装成插件的,但一想,这种效果,也不大可能同时用多个,就偷懒直接写了。相关自定义的变量都放在一起了,一些功能函数也都有注释。自测兼容性良好,若有BUG请反馈。
点此查看样列
jQuery代码:
var imgField=$('#J_imgList');
var imgList=$('#J_imgList>li');
var navField=$('#J_navList');
var navList=$('#J_navList>li');
var btnPrev=$('#J_prev');
var btnNext=$('#J_next');
var turnPage=4;//每屏显示数
var T=5000;//切换间隔时间
var turnT=300;//animate时间
var N=0;//图片初始索引
var P=1;//屏初始索引
var goFun=null;
var hoverFun=null;
var triggerFun=null;
var delayFun=null
var navListW=navList.outerWidth(true);
var turnPages=Math.ceil(navList.size()/turnPage);
//初始图片区域高度与标题区域宽度
imgField.height(imgList.size()*imgList.height());
navField.width(navList.size()*navListW);
//初始自动切换
GO();
//自动切换
function GO() {
imgField.stop().animate({
marginTop:-N*(imgList.height())
},turnT);
navList.eq(N).addClass('hover').siblings().removeClass('hover');
if(N%turnPage==0) {
navField.stop().animate({
marginLeft:-N*navListW+'px'
},turnT);
}
N++;
N= N>=imgList.size()?0:N;
P=Math.ceil(N/turnPage);
goFun=setTimeout(GO,T);
}
//停止切换
function STOP() {
clearTimeout(goFun);
}
//标题划过移出
navList.hover( function() {
clearTimeout(delayFun);
STOP();
N=navList.index(this);
imgField.stop().animate({
marginTop:-N*(imgList.height())
},turnT);
$(this).addClass('hover').siblings().removeClass('hover');
}, function() {
N++;
delayFun=setTimeout(GO,T)
});
//图片划过移出
imgList.hover( function() {
N=imgList.index(this);
navList.eq(N).trigger('mouseover');
}, function() {
navList.eq(N).trigger('mouseleave');
});
//左切换
btnPrev.click( function() {
if(P==1) {
navField.animate({
marginLeft:-turnPage*navListW*(turnPages-1)+'px'
},turnT);
P=turnPages;
} else {
STOP();
P--;
navField.animate({
marginLeft:-turnPage*navListW*(P-1)+'px'
},turnT);
}
navList.eq((P-1)*turnPage).trigger('mouseover');
GO();
});
//右切换
btnNext.click( function() {
if(P==turnPages) {
navField.animate({
marginLeft:0
},turnT);
P=1;
} else {
STOP();
P++;
navField.animate({
marginLeft:-turnPage*navListW*P+'px'
});
}
navList.eq((P-1)*turnPage).trigger('mouseover');
GO();
});
jQuery
Posted by Mr.Think on 03/21/2011

最近公司项目页面中用到选项卡与幻灯比较多,特地写了个集选项卡、幻灯片与播放控制于一体的插件,同页面可多次使用。思路就不说了,记得以前写过一个自动切换的幻灯插件:http://mrthink.net/jq-plugin-ifadeslide/,思路有部分是类似的。当然,本文中插件源码中也有注释~
插件核心代码:点此查看样例
$.fn.WIT_SetTab=function(iSet){
/*
* @Mr.Think
* Nav: 导航钩子;
* Field:切换区域
* K:初始化索引;
* CurCls:高亮样式;
* Auto:是否自动切换;
* AutoTime:自动切换时间;
* OutTime:淡入时间;
* InTime:淡出时间;
* CrossTime:鼠标无意识划过时间
* Ajax:是否开启ajax
* AjaxFun:开启ajax后执行的函数
*/
iSet=$.extend({Nav:null,Field:null,K:0,CurCls:'cur',Auto:false,AutoTime:4000,OutTime:100,InTime:150,CrossTime:60},iSet||{});
var acrossFun=null,hasCls=false,autoSlide=null;
//切换函数
function changeFun(n){
iSet.Field.filter(':visible').fadeOut(iSet.OutTime, function(){
iSet.Field.eq(n).fadeIn(iSet.InTime).siblings().hide();
});
iSet.Nav.eq(n).addClass(iSet.CurCls).siblings().removeClass(iSet.CurCls);
}
//初始高亮第一个
changeFun(iSet.K);
//鼠标事件
iSet.Nav.hover(function(){
iSet.K=iSet.Nav.index(this);
if(iSet.Auto){
clearInterval(autoSlide);
}
hasCls = $(this).hasClass(iSet.CurCls);
//避免无意识划过时触发
acrossFun=setTimeout(function(){
//避免当前高亮时划入再次触发
if(!hasCls){
changeFun(iSet.K);
}
},iSet.CrossTime);
},function(){
clearTimeout(acrossFun);
//ajax调用
if(iSet.Ajax){
iSet.AjaxFun();
}
if(iSet.Auto){
//自动切换
autoSlide = setInterval(function(){
iSet.K++;
changeFun(iSet.K);
if (iSet.K == iSet.Field.size()) {
changeFun(0);
iSet.K=0;
}
}, iSet.AutoTime)
}
}).eq(0).trigger('mouseleave');
}
jQuery
Posted by Mr.Think on 01/11/2011
此插件是对10年8月20日的文章的更新, 之前的版本有诸多bug…抱着对读者负责的态度,又重写了一次.
更新内容:
1. 用户快速划过按钮时不触发鼠标事件;
2. 鼠标划入当前图片按钮时不闪烁;
3. 简化并优化代码.
使用方法就不详述了, 请参见源码及相关注释:点此查看DEMO
$.fn.iFadeSlide = function(iSet){
/*
* iSet可选参数说明:
* iSet.field==>幻灯区域内的图片集
* iSet.ico==>按钮钩子
* iSet.high==>按钮高亮样式
* iSet.interval==>图片切换时间
* iSet.leaveTime==>不触发鼠标划入事件的最大时间值
* iSet.fadeInTime==>淡入时间
* iSet.fadeOutTime==>淡出时间
* 调用方式$(document).iFadeSlide({field:'...',ico:'...',...})
*/
iSet = $.extend({high:'high',interval:3000,leaveTime:150,fadeOutTime:400,fadeInTime:400},iSet);
var imgField = $(iSet.field || '#slide>img');
var icoField = $(iSet.ico || '#ico');
var curIndex = 0;
var slideInterval = iSet.interval || 3000;
var hoverTime = iSet.leaveTime || 150;
var fadeOutTime = iSet.fadeOutTime || 400;
var fadeInTime = iSet.fadeInTime || 400;
var icos=null, fastHoverFun = null, autoSlideFun = null, hasIcoHighCls = null, changeFun = null,max=null;;
var icoHtml = '<ul>';
max=imgField.size();
//按图片传入对应的按钮
imgField.each(function(i){
icoHtml += '<li>' + (i + 1) + '</li>';
});
icoHtml += '</ul>';
icoField.append(icoHtml);
//淡入淡出函数
changeFun = function(n){
imgField.filter(':visible').fadeOut(fadeOutTime, function(){
imgField.eq(n).fadeIn(fadeInTime)
icos.eq(n).addClass(iSet.high).siblings().removeClass(iSet.high);
});
}
icos = icoField.find('ul>li');
//为第一个按键初始化高亮
icos.first().addClass(iSet.high);
//按钮鼠标划入划出事件
icos.hover(function(){
clearInterval(autoSlideFun);
curIndex = icos.index(this);
hasIcoHighName = $(this).hasClass(iSet.high);
//setTimeout避免用户快速(无意识性划过)划过时触发事件
fastHoverFun = setTimeout(function(){
//鼠标划入当前图片按钮时不闪烁
if (!hasIcoHighName) {
changeFun(curIndex);
}
}, hoverTime);
}, function(){
clearTimeout(fastHoverFun);
//自动切换
autoSlideFun = setInterval(function(){
curIndex++;
changeFun(curIndex);
if (curIndex ==max ) {
changeFun(0);
curIndex = 0;
}
}, slideInterval)
}).eq(0).trigger('mouseleave');
//当鼠标划入图片区域时停止切换
imgField.hover(function(){
curIndex = imgField.index(this);
clearInterval(autoSlideFun);
}, function(){
icos.eq(curIndex).trigger('mouseleave');
});
}
jQuery