点击加减或手动改变表单值(支持键盘控制)的jQuery插件

大多电子商务网站购物车页面,都有通过点击来增减商品数量的功能,特地根据常规功能写了一个jQuery插件。
购物车常用功能
实现的功能:
1、可通过点击增加或减小定义的input值;
2、可手动输入input值,且支持键盘控制:上右为加,下左为减;
3、可设定表单的最大最小值,并对input值进行了非负整数判断;
4、定义了一个全局对象,存储表单最后的input值和所改变input的索引值。若不希望全局对象污染整个js,可在插件中稍稍修改一下,把想返回的值传到一个hidden input中;
5、定义了一个回调函数,方便扩展。比如,在点击或输入数值后重新计算价格数量等。
点此查看样列
jQuery代码:

$.fn.iVaryVal=function(iSet){
	/*
	 * Minus:点击元素--减小
	 * Add:点击元素--增加
	 * Input:表单元素
	 * Min:表单的最小值,非负整数
	 * Max:表单的最大值,正整数
	 * Fun:回调函数
	 */
	iSet=$.extend({Minus:$('.J_minus'),Add:$('.J_add'),Input:$('.J_input'),Min:0,Max:20,Fun:null},iSet);
	var C=null,O=null;
	//输出值全局对象[若担心全局对象污染,可定义一个hidden表单,向其传值]
	$GLOBAL={};
	//增加
	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);
			//输出当前改变后的值
			$GLOBAL.val=iSet.Input.eq(i).val();
			$GLOBAL.index=i;
			//回调函数
			if (typeof iSet.Fun == 'function') {
				iSet.Fun.call(this);
		  	}
		});
	});
	//减少
	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);
			$GLOBAL.val=iSet.Input.eq(i).val();
			$GLOBAL.index=i;
			//回调函数
			if (typeof iSet.Fun == 'function') {
				iSet.Fun.call(this);
		  	}
		});
	});
	//手动
	iSet.Input.bind({
		'click':function(){
			O=parseInt($(this).val());
			$(this).select();
		},
		'keyup':function(){
			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();
			}
			//输出当前改变后的值
			$GLOBAL.val=$(this).val();
			$GLOBAL.index=iSet.Input.index(this);
			//回调函数
			if (typeof iSet.Fun == 'function') {
				iSet.Fun.call(this);
		  	}
		},
		'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);
			}
			//输出当前改变后的值
			$GLOBAL.val=$(this).val();
			$GLOBAL.index=iSet.Input.index(this);
			//回调函数
			if (typeof iSet.Fun == 'function') {
				iSet.Fun.call(this);
		  	}
		}
	});
}

若有bug,请以评论形式及时反馈~

多屏自动切换jQuery效果,可手动切换

油翁酌油沥钱,自钱孔入而钱不湿。因曰:“我亦无他, 唯手熟尔”。
好久没有好好的写过代码了,博客也有好几个月没有更新。忙于工作,忙于人身大事,忙于琐碎。最近相对清闲,正好一个做后端的朋友求助于我,帮他写一个新蛋网首页多屏自动切换效果。顺便分享之。
多屏自动切换jQuery效果
思路很简单,详见代码。本来是想封装成插件的,但一想,这种效果,也不大可能同时用多个,就偷懒直接写了。相关自定义的变量都放在一起了,一些功能函数也都有注释。自测兼容性良好,若有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的可用于选项卡及幻灯的切换插件

基于jQuery的可用于选项卡及幻灯的切换插件
最近公司项目页面中用到选项卡与幻灯比较多,特地写了个集选项卡、幻灯片与播放控制于一体的插件,同页面可多次使用。思路就不说了,记得以前写过一个自动切换的幻灯插件: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淡入淡出可自动切换的幻灯插件(2011.01.11更新)

此插件是对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');
    });
}

多组处理, 仅展开一个区块的折叠效果(原生Js和jQ版)

上午在项目中遇到的一个问题, 折腾了半小时才把思路理顺. 需求是, 同一个页面, 有多组(不固定), 每组区块数量不一定一样的小区块. 要求每次只展开一个区块. 实现原理其实很简单, 点击导航, 若它的区块为隐藏, 则展开它, 同时, 隐藏掉同组其他区块; 若它的区块为展开, 则隐藏它, 同时, 展开同组其他区块中的一个. 一开始以为仅仅简单的两个遍历就能搞定. 但事实并非如此. 冷静思考了下, 通过点击的元素取到当前组的相关元素, 再单独处理当前组才合理. 顺着这个思路, 功能终于实现了, 写了原生JS版本, 用同样的思路写了个jQ版本. 时间关系, 写的也比较零散, 就没有封装. 其实, 对这种思路也不是很满意, 感觉太散了, 哪位大师有更好的思路请赐教.

另, 在演示页面中, 点击jQ版区块的标题, 会有一个JS错误, 那是因为获取JS版下的h2时, 我偷了个懒, 把jQ的也遍历进去了. 我想, 实际应用中, 也不会有人同一个效果, 一边用JS一边用jQ吧.
核心代码点此查看样例

//原生JS版本 ***** start
window.onload=function(){
	//共用函数区
	var iBase={
		//document.getElementById
		Id: function(name){return document.getElementById(name)},
		//通过class获取元素
		GetByClass: function(name,tagName,elem){
			var c=[];
			var re=new RegExp('(^|\\s)'+name+'(|\\s$)');
			var e=(elem || document).getElementsByTagName(tagName || '*');
			for(var i=0; i < e.length; i++){
				if(re.test(e[i].className)){
					c.push(e[i]);
				}
			}
			return c;
		},
		//获取样式属性
		AttrStyle: function(elem,attr){
			if(elem.attr){
				return elem.style[attr];
			}else if(elem.currentStyle){
				return elem.currentStyle[attr];
			}else if(document.defaultView && document.defaultView.getComputedStyle){
				attr=attr.replace(/([A-Z])/g,'-$1').toLowerCase();
				return document.defaultView.getComputedStyle(elem,null).getPropertyValue(attr);
			}else{
				return null;
			}
		},
		//获取祖辈元素中符合指定样式的元素
		Parents: function(elem,name){
			var r=new RegExp('(^|\\s)'+name+'(|\\s$)');
			elem=elem.parentNode;
			if(elem!=null){
				return r.test(elem.className) ? elem : iBase.Parent(elem,name) || null;
			}
		},
		//取索引值
		Index: function(cur,obj){
			for(var i=0; i < obj.length; i++){
				if(obj[i]==cur){
					return i;
				}
			}
		}

	}

	//变量定义
	var listBox=iBase.GetByClass('js','div');
	var navItem=iBase.Id('demo').getElementsByTagName('h2');//此处将jQ区块中的h2也取到了,所以页面会有个小小的错误
	var icoItem=null,boxItem=null,boxDisplay=null,elemIndex=null,elemParent=null;
	//初始化展开第一个
	for(var i=0; i < listBox.length;i++){
		iBase.GetByClass('box','div',listBox[i])[0].style.display='block';
		listBox[i].getElementsByTagName('span')[0].innerHTML='-';
	}
	//遍历所有点击项
	for(var i=0; i < navItem.length;i++){
		navItem[i].onclick=function(){
			elemParent=iBase.Parents(this,'js');//获取当前点击所在区块
			navItem=elemParent.getElementsByTagName('h2');//获取当前区块下的点击项
			icoItem=elemParent.getElementsByTagName('span');//获取当前区块下的展开关闭
			boxItem=iBase.GetByClass('box','div',elemParent);//获取需要控制的区块
			elemIndex=iBase.Index(this,navItem);//获取当前点击在当前区块点击项中的索引
			//切换展开关闭图标
			icoItem[elemIndex].innerHTML= icoItem[elemIndex].innerHTML=='-' ? '+' : '-';
			if(iBase.AttrStyle(boxItem[elemIndex],'display')=='block'){
				//控制项展开状态下,隐藏当前,展开其他的第一项
				//此处有个展开0/1的判断,因为当点击第一个时是不能再展开第一个的
				boxItem[elemIndex].style.display='none';
				if(elemIndex==0){
					boxItem[1].style.display='block';
					icoItem[1].innerHTML='-'
				}else{
					boxItem[0].style.display='block'
					icoItem[0].innerHTML='-'
				}
			}else{
				//控制项展开状态下,展开当前,隐藏其他项
				boxItem[elemIndex].style.display='block';
				for(var k=0;k < boxItem.length; k++){
					if(k!=elemIndex){
						boxItem[k].style.display='none';
						icoItem[k].innerHTML='+';
					}
				}
			}
		}
	}

}

//jQuery版本 ***** start
$(function(){
	//变量定义区
	var _listBox=$('.jq');
	var _navItem=$('.jq>h2');
	var _boxItem=null, _icoItem=null, _parents=null, _index=null;

	//初始化第一个展开
	_listBox.each(function(i){
		$(this).find('div.box').eq(0).show();
		$(this).find('h2>span').eq(0).text('-');
	});

	//遍历所有的点击项
	_navItem.each(function(i){
		$(this).click(function(){
			//找到当前点击父元素为listbox(单个区块)的元素
			_parents=$(this).parents('.listbox');
			_navItem=_parents.find('h2');//此区块中的点击项
			_icoItem=_parents.find('span');//此区块中的展开关闭图标
			_boxItem=_parents.find('div.box');//此区块中展开关闭项
			_index=_navItem.index(this);//取得当前点击在当前区块下点击项中的索引值
			if(_boxItem.eq(_index).is(':visible')){
				//若当前点击项下的展开关闭项是显示的,则关闭,同时展开另外项中的第一个
				_boxItem.eq(_index).hide().end().not(':eq('+_index+')').first().show();
				_icoItem.eq(_index).text('+').end().not(':eq('+_index+')').first().text('-');
			}else{
				//若当前点击项下的展开关闭项是隐藏的,则展开,同时隐藏其他项
				_boxItem.eq(_index).show().end().not(':eq('+_index+')').hide();
				_icoItem.eq(_index).text('-').end().not(':eq('+_index+')').text('+');
			}
		});
	});
});