键盘控制-页面网格导航-jQuery插件

当时写此程序是为了满足用电视(机顶盒)的遥控操作电视中的WEB页面(电视中的网页app)的需求

/**
 * 按键导航(页面网格导航)
 * FILE: keynav.js
 * USEAGE:
 *  每个参与导航的元素HTML写法如下:
 *  HTML: <a href="#" οnclick="location.href=this.href或JS方法调用" class="keynav" id="myId" keynav="idU,idR,idD,idL,1,1,move">item</a>   
 *  调用如下方法进行按键监听:
 * JS: $('.keynav').keyNav(config); // 不指定config则使用默认值,通过AJAX取回数据并显示后,重新调用该方法使导航生效
 * 属性说明:
 *  keynav的值为逗号分隔串:"idU,idR,idD,idL,canBack,isClick,funcMove"
 *  idU:上元素ID
 *  idR:右元素ID
 *   idD:下元素ID
 *   idL:左元素ID
 *  canBack:按后退键时1是0否可以后退到该元素
 *  isClick:元素获得焦点后是否立即触发其单击事件
 *  funcMove:函数名,当按上下左右键时使用此函数移动该元素
 * @author tshichun 2010.10.26
 */
(function($) {
	$.KeyNav = new Object();
	/*main*/
	$.fn.keyNav = function(config) {
		var kn = $.KeyNav;
		/*if (!kn.initialized)*/
		if (kn.lastActive && kn.config) {
			$(kn.lastActive).removeClass(kn.config.activeCls);
		}
		$(document).unbind('keydown');
		kn.config = config ? $.extend({},
		$.KeyNav.defaults, config) : $.KeyNav.defaults;
		kn.navObjs = new Array();
		/*所有导航对象*/
		kn.active = null;
		/*当前被激活的导航项*/
		kn.lastActive = null;
		/*上次被激活的导航项*/
		if (typeof(kn.backActives) == 'undefined') {
			kn.backActives = new Array();
		}
		/*按返回键则向上逐级激活这些元素*/
		/*kn.initialized = true; endif*/
		/*注册所有导航项*/
		this.each(function() {
			$.KeyNav.register(this);
		});
		/*设置默认激活的导航项*/
		kn.active = $.KeyNav.getActive();
		kn.lastActive = kn.active;
		/*开始监听按键事件*/
		$(document).keydown(function(e) {
			var key = e == null ? event.keyCode: e.which;
			switch (key) {
			case 37:
				$.KeyNav.doLeft(e);
				break;
			case 38:
				$.KeyNav.doUp(e);
				break;
			case 39:
				$.KeyNav.doRight(e);
				break;
			case 40:
				$.KeyNav.doDown(e);
				break;
			case 13:
				$.KeyNav.doEnter(e);
				break;
			case 8:
				$.KeyNav.doBack(e);
				break;
			default:
				break;
			}
		});
		return this;
	};
	/*默认配置*/
	$.KeyNav.defaults = {
		activeCls: 'active',
		/*被激活元素的class属性*/
		activeDefault: 'keyNavDefault'
		/*默认激活的元素ID*/
	};
	/*注册一个导航元素*/
	$.KeyNav.register = function(element) {
		var kn = $.KeyNav;
		var obj = $(element);
		var c = obj.attr('keynav');
		if (c) {
			c = c.split(',');
			obj.U = c[0];
			obj.R = c[1];
			obj.D = c[2];
			obj.L = c[3];
			if (c[4] && c[4] == 1) {
				obj.canBack = true;
			}
			if (c[5] && c[5] == 1) {
				obj.isClick = true;
			}
			if (c[6] && c[6] != '') {
				obj.funcMove = c[6];
			}
		}
		kn.navObjs[obj.attr('id')] = obj;
	};
	/*激活一个导航项*/
	$.KeyNav.setActive = function(obj) {
		var kn = $.KeyNav;
		if (obj != kn.active) {
			kn.lastActive = kn.active;
			$(kn.lastActive).trigger('blur');
			$(kn.lastActive).removeClass(kn.config.activeCls);
			$(obj).trigger('focus');
			$(obj).addClass(kn.config.activeCls);
			kn.active = obj;
			/*元素可后退*/
			if (obj.canBack) {
				kn.uniquePush(kn.backActives, obj);
			}
			/*若要求立即触发单击事件,且不是默认激活的元素*/
			if (obj.isClick && obj.attr('id') != $('#' + kn.config.activeDefault).attr('id')) {
				$(obj).click();
			}
		}
	};
	/*当前被激活的导航项*/
	$.KeyNav.getActive = function() {
		var kn = $.KeyNav;
		/*若当前没有被激活的导航项,则返回默认激活项*/
		if (!kn.active && kn.navObjs[kn.config.activeDefault]) {
			$.KeyNav.setActive(kn.navObjs[kn.config.activeDefault]);
		}
		return kn.active;
	};
	/*导航*/
	$.KeyNav.nav = function(navObjsIndex) {
		var kn = $.KeyNav;
		var active = $.KeyNav.getActive();
		if (active.funcMove) {
			var e = typeof(arguments[1]) ? arguments[1] : null;
			try {
				eval(active.funcMove + '(e);');
			} catch(err) {}
		} else {
			/*如果给定的元素存在*/
			if (navObjsIndex && $('#' + navObjsIndex)[0] && kn.navObjs[navObjsIndex]) {
				$.KeyNav.setActive(kn.navObjs[navObjsIndex]);
			}
		}
	};
	/*阻止浏览器默认事件行为*/
	$.KeyNav.stopDefault = function(e) {
		e == null ? window.event.returnValue = false: e.preventDefault();
	};
	/*向数组插入元素,若已存在,则忽略*/
	$.KeyNav.uniquePush = function(array, obj) {
		var exists = false;
		for (var i = 0; i < array.length; i++) {
			if ($(array[i]).attr('id') == $(obj).attr('id')) {
				exists = true;
				break;
			}
		}
		if (!exists) {
			array.push(obj);
		}
	};
	/*按键处理*/
	$.KeyNav.doLeft = function(e) {
		var active = $.KeyNav.getActive();
		$.KeyNav.nav(active.L, e);
	};
	$.KeyNav.doUp = function(e) {
		var active = $.KeyNav.getActive();
		$.KeyNav.nav(active.U, e);
	};
	$.KeyNav.doRight = function(e) {
		var active = $.KeyNav.getActive();
		$.KeyNav.nav(active.R, e);
	};
	$.KeyNav.doDown = function(e) {
		var active = $.KeyNav.getActive();
		$.KeyNav.nav(active.D, e);
	};
	$.KeyNav.doEnter = function(e) {
		var active = $.KeyNav.getActive();
		$(active).click();
	};
	$.KeyNav.doBack = function(e) {
		$.KeyNav.stopDefault(e);
		var kn = $.KeyNav;
		var backHistory = true;
		if (kn.backActives.length > 0) {
			var index = kn.backActives.length - 1;
			/*后进先出*/
			/*只后退到非当前元素*/
			if ($(kn.backActives[index]).attr('id') == $(kn.active).attr('id')) {
				kn.backActives.splice(index, 1);
				index--;
			}
			if (index >= 0) {
				kn.setActive(kn.backActives[index]);
				backHistory = false;
			}
		}
		if (backHistory) {
			history.back();
		}
	};
	/*end*/
})(jQuery);

辅助函数(JS):

/**
 * 按键导航(页面网格导航)工具函数
 * FILE: keynav.tool.js
 * 包括如下工具函数:
 * 1.getKeynav 取得导航元素keynav属性值
 * 2.getPageBar 取得分页条HTML
 * USAGE:
 * $.KeyNav.getKeynav(参数列表);
 * $.KeyNav.getPageBar(参数列表);
 * @author tshichun 2010.11.06
 */
(function($) {
	/**
	 * 取得导航元素keynav属性值
	 * @param index 当前下标
	 * @param idPrefix ID前缀
	 * @param idUDefault 默认向上元素ID
	 * @param idRDefault 默认向右元素ID
	 * @param idDDefault 默认向下元素ID
	 * @param idLDefault 默认向左元素ID
	 * @param gridCols 网格列数
	 * @param gridRows 网格行数
	 * @param count 循环次数
	 * @author SYS 2010.11.06
	 */
	$.KeyNav.getKeynav = function(index, idPrefix, idUDefault, idRDefault, idDDefault, idLDefault, gridCols, gridRows, count) {
		var idU = idR = idD = idL = '';
		if (gridCols > 1 && gridRows > 1) {
			// 行首元素的idL为idLDefault 
			idL = (index % gridCols == 0) ? idLDefault: idPrefix + (index - 1);
			// 行尾元素的idR为idRDefault
			idR = ((index + 1) % gridCols == 0) || ((index + 1) == count) ? idRDefault: idPrefix + (index + 1);
			// 首行元素的idU为idUDefault
			idU = (index < gridCols) ? idUDefault: idPrefix + (index - gridCols);
			// 尾行元素的idD为idDDefault  
			idD = (Math.floor(index / gridCols) + 1) == Math.ceil(count / gridCols) || Math.ceil(count / gridCols) == 1 ? idDDefault: idPrefix + (index + gridCols);
		} else if (gridRows == 1) {
			// 只有一行的情况
			idU = idUDefault;
			idD = idDDefault;
			idL = (index > 0) ? idPrefix + (index - 1) : idLDefault;
			idR = (index < count - 1) ? idPrefix + (index + 1) : idRDefault;
		} else if (gridCols == 1) {
			// 只有一列的情况
			idL = idLDefault;
			idR = idRDefault;
			idU = (index > 0) ? idPrefix + (index - 1) : idUDefault;
			idD = (index < count - 1) ? idPrefix + (index + 1) : idDDefault;
		}
		return idU + ',' + idR + ',' + idD + ',' + idL;
	};
	/**
	 * 取得分页条HTML
	 * @param total 总记录数
	 * @param page 当前第几页
	 * @param pageSize 每页多少条记录
	 * @param jsMethod 通过JS方法取数据时有用,若指定该值,则忽略url
	 * @param pagesNum 显示多少页
	 * @param url 跳转链接地址
	 * @param array keyNavParams 需要通过键盘导航时指定该参数
	 * @param pageVar 页码对应的参数名,如?page=n中的page
	 * @author tshichun 2010.11.06
	 */
	$.KeyNav.getPageBar = function(total, page, pageSize, jsMethod, pagesNum, url, keyNavParams, pageVar) {
		var pageBar = '';
		if (total > pageSize) {
			// 计算总页数
			totalPages = Math.ceil(total / pageSize);
			// 控制在最多pagesNum页
			if (totalPages > pagesNum) {
				totalPages = pagesNum;
			}
			if (jsMethod != '') {
				// 通过JS方法调用
				url = 'javascript:' + jsMethod + '(%p%)';
			} else {
				// 通过超链接形式
				if (url == '') {
					url = location.href;
				}
				url = url.replace(new RegExp('&*' + pageVar + '=' + page), '');
				if (url.indexOf('?') != -1) {
					url = url.indexOf('=') != -1 ? url + '&' + pageVar + '=%p%': url + pageVar + '=%p%';
				} else {
					url = url + '?' + pageVar + '=%p%';
				}
			}
			// 需要通过键盘导航吗
			var byKey = keyNavParams.length > 0;
			var byKeyStr = '';
			// 首页
			if (byKey) {
				byKeyStr = ' class="keynav" id="' + keyNavParams['prefix'] + '0" keynav="' + keyNavParams['idUDefault'] + ',' + keyNavParams['prefix'] + '1,' + keyNavParams['idDDefault'] + ',' + keyNavParams['idLDefault'] + '"';
			} else {
				byKeyStr = '';
			}
			pageBar += '<a href="' + (page == 1 ? 'javascript:;': url.replace('%p%', 1)) + '" οnclick="location.href=this.href"' + byKeyStr + '>首页</a>';
			// 上一页
			if (byKey) {
				byKeyStr = ' class="keynav" id="' + keyNavParams['prefix'] + '1" keynav="' + keyNavParams['idUDefault'] + ',' + keyNavParams['prefix'] + '2,' + keyNavParams['idDDefault'] + ',' + keyNavParams['prefix'] + '0"';
			} else {
				byKeyStr = '';
			}
			pageBar += '<a href="' + (page > 1 ? url.replace('%p%', page - 1) : 'javascript:;') + '" οnclick="location.href=this.href"' + byKeyStr + '>上一页</a>';
			// 下一页
			if (byKey) {
				byKeyStr = ' class="keynav" id="' + keyNavParams['prefix'] + '2" keynav="' + keyNavParams['idUDefault'] + ',' + keyNavParams['prefix'] + '3,' + keyNavParams['idDDefault'] + ',' + keyNavParams['prefix'] + '1"';
			} else {
				byKeyStr = '';
			}
			pageBar += '<a href="' + (page < totalPages ? url.replace('%p%', page + 1) : 'javascript:;') + '" οnclick="location.href=this.href"' + byKeyStr + '>下一页</a>';
			// 尾页
			if (byKey) {
				byKeyStr = ' class="keynav" id="' + keyNavParams['prefix'] + '3" keynav="' + keyNavParams['idUDefault'] + ',' + keyNavParams['prefix'] + '4,' + keyNavParams['idDDefault'] + ',' + keyNavParams['prefix'] + '2"';
			} else {
				byKeyStr = '';
			}
			pageBar += '<a href="' + (page == totalPages ? 'javascript:;': url.replace('%p%', totalPages)) + '" οnclick="location.href=this.href"' + byKeyStr + '>尾页</a>';
			// 显示下拉页码
			if (byKey) {
				byKeyStr = ' class="keynav" id="' + keyNavParams['prefix'] + '4" keynav=",' + keyNavParams['idRDefault'] + ',' + keyNavParams['idDDefault'] + ',' + keyNavParams['prefix'] + '3"';
			} else {
				byKeyStr = '';
			}
			//下拉列表单击事件处理
			var onclick = '';
			if (jsMethod) {
				onclick = url.replace('%p%)', '') + "this.value)";
			} else {
				onclick = "location.href='" + url.replace('%p%', '') + "' + this.value";
			}
			pageBar += ' 跳转至 <select' + byKeyStr + ' οnclick="' + onclick + '">';

			for (var i = 0; i < totalPages; i++) {
				var selected = (i + 1) == page ? ' selected': '';
				pageBar += '<option value="' + (i + 1) + '"' + selected + '>' + (i + 1) + '</option>';
			}

			pageBar += '</select> 页';
		}
		return pageBar;
	};
})(jQuery);

辅助函数(PHP):

/**
 * 取得由导航元素的上右下左邻元素ID组成的字符串
 * 如:idU,idR,idD,idL
 * @param $params array
 * (
 *  index 当前下标
 *  idPrefix ID前缀
 *  idUDefault 默认向上元素ID
 *  idRDefault 默认向右元素ID
 *  idDDefault 默认向下元素ID
 *  idLDefault 默认向左元素ID
 *  gridCols 网格列数
 *  gridRows 网格行数
 *  count 循环次数
 * )
 * @author tshichun 2010.10.26
 */
function getKNStrForEach(array $params) {
	extract($params);
	$idU = $idR = $idD = $idL = '';
	if ($gridCols > 1 && $gridRows > 1) {
		// 行首元素的$idL为$idLDefault 
		$idL = ($index % $gridCols == 0) ? $idLDefault: $idPrefix. ($index - 1);
		// 行尾元素的$idR为$idRDefault
		$idR = (($index + 1) % $gridCols == 0) || (($index + 1) == $count) ? $idRDefault: $idPrefix. ($index + 1);
		// 首行元素的$idU为$idUDefault
		$idU = ($index < $gridCols) ? $idUDefault: $idPrefix. ($index - $gridCols);
		// 尾行元素的$idD为$idDDefault  
		$idD = (floor($index / $gridCols) + 1) == ceil($count / $gridCols) || ceil($count / $gridCols) == 1 ? $idDDefault: $idPrefix. ($index + $gridCols);
	} else if ($gridRows == 1) {
		// 只有一行的情况
		$idU = $idUDefault;
		$idD = $idDDefault;
		$idL = ($index > 0) ? $idPrefix. ($index - 1) : $idLDefault;
		$idR = ($index < $count - 1) ? $idPrefix. ($index + 1) : $idRDefault;
	} else if ($gridCols == 1) {
		// 只有一列的情况
		$idL = $idLDefault;
		$idR = $idRDefault;
		$idU = ($index > 0) ? $idPrefix. ($index - 1) : $idUDefault;
		$idD = ($index < $count - 1) ? $idPrefix. ($index + 1) : $idDDefault;
	}
	return "$idU,$idR,$idD,$idL";
}
/**
  * 取得分页导航条
  * @param $total 总记录数
  * @param $page 当前第几页
  * @param $pageSize 每页多少条记录
  * @param $jsMethod 通过JS方法取数据时有用,若指定该值,则忽略$url
  * @param $pagesNum 显示多少页
  * @param $url 跳转链接地址
  * @param array $keyNavParams 需要通过键盘导航时指定该参数
  * @param $pageVar 页码对应的参数名,如?page=n中的page
  * @author tshichun 2010.10.27
  */
function getPageBar($total, $page, $pageSize, $jsMethod = '', $pagesNum = 20, $url = '', array $keyNavParams = null, $pageVar = 'page') {
	$pageBar = '';
	if ($total > $pageSize) {
		// 计算总页数
		$totalPages = ceil($total / $pageSize);
		// 控制在最多$pagesNum页
		if ($totalPages > $pagesNum) {
			$totalPages = $pagesNum;
		}
		if ($jsMethod != '') {
			// 通过JS方法调用
			$url = 'javascript:'.$jsMethod.'(%p%)';
		} else {
			// 通过超链接形式
			if ($url == '') {
				$url = $_SERVER['REQUEST_URI'];
			}
			$url = ereg_replace("(^|&)".$pageVar."=$page", '', $url);
			if (strpos($url, '?')) {
				$url = strpos($url, '=') ? $url.'&'.$pageVar.'=%p%': $url.$pageVar.'=%p%';
			} else {
				$url = $url.'?'.$pageVar.'=%p%';
			}
		}
		// 需要通过键盘导航吗
		$byKey = !empty($keyNavParams);
		// 首页
		if ($byKey) {
			$byKeyStr = ' class="keynav" id="'.$keyNavParams['prefix'].'0" keynav="'.$keyNavParams['idUDefault'].','.$keyNavParams['prefix'].'1,'.$keyNavParams['idDDefault'].','.$keyNavParams['idLDefault'].'"';
		} else {
			$byKeyStr = '';
		}
		$pageBar. = '<a href="'. ($page == 1 ? 'javascript:;': str_replace('%p%', 1, $url)).'" οnclick="location.href=this.href"'.$byKeyStr.'>首页</a>';
		// 上一页
		if ($byKey) {
			$byKeyStr = ' class="keynav" id="'.$keyNavParams['prefix'].'1" keynav="'.$keyNavParams['idUDefault'].','.$keyNavParams['prefix'].'2,'.$keyNavParams['idDDefault'].','.$keyNavParams['prefix'].'0"';
		} else {
			$byKeyStr = '';
		}
		$pageBar. = '<a href="'. ($page > 1 ? str_replace('%p%', $page - 1, $url) : 'javascript:;').'" οnclick="location.href=this.href"'.$byKeyStr.'>上一页</a>';
		// 下一页
		if ($byKey) {
			$byKeyStr = ' class="keynav" id="'.$keyNavParams['prefix'].'2" keynav="'.$keyNavParams['idUDefault'].','.$keyNavParams['prefix'].'3,'.$keyNavParams['idDDefault'].','.$keyNavParams['prefix'].'1"';
		} else {
			$byKeyStr = '';
		}
		$pageBar. = '<a href="'. ($page < $totalPages ? str_replace('%p%', $page + 1, $url) : 'javascript:;').'" οnclick="location.href=this.href"'.$byKeyStr.'>下一页</a>';
		// 尾页
		if ($byKey) {
			$byKeyStr = ' class="keynav" id="'.$keyNavParams['prefix'].'3" keynav="'.$keyNavParams['idUDefault'].','.$keyNavParams['prefix'].'4,'.$keyNavParams['idDDefault'].','.$keyNavParams['prefix'].'2"';
		} else {
			$byKeyStr = '';
		}
		$pageBar. = '<a href="'. ($page == $totalPages ? 'javascript:;': str_replace('%p%', $totalPages, $url)).'" οnclick="location.href=this.href"'.$byKeyStr.'>尾页</a>';
		// 显示下拉页码
		if ($byKey) {
			$byKeyStr = ' class="keynav" id="'.$keyNavParams['prefix'].'4" keynav=",'.$keyNavParams['idRDefault'].','.$keyNavParams['idDDefault'].','.$keyNavParams['prefix'].'3"';
		} else {
			$byKeyStr = '';
		}
		//下拉列表单击事件处理
		if ($jsMethod) {
			$onclick = str_replace('%p%)', '', $url)."this.value)";
		} else {
			$onclick = "location.href='".str_replace('%p%', '', $url)."' + this.value";
		}
		$pageBar. = ' 跳转至 <select'.$byKeyStr.' οnclick="'.$onclick.'">';

		for ($i = 0; $i < $totalPages; $i++) {
			$selected = ($i + 1) == $page ? ' selected': '';
			$pageBar. = '<option value="'. ($i + 1).'"'.$selected.'>'. ($i + 1).'</option>';
		}

		$pageBar. = '</select> 页';
	}
	return $pageBar;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值