高仿select

最近也不知道在瞎忙些什么,七月份一篇日志没写。昨天公司项目要求模拟一个select。其实这玩意以前也写过。只是感觉没做好。所以又重写了一个。和系统默认的很相近吧。说明一下吧:
一:鼠标点击这个肯定不用说了
二:支持键盘上下键,回车键选择
三:用tab键获得焦点后。也支持键盘上下键选择,无须弹出下拉菜单。
其实也没啥,无非就是个select而已。由于这个是用在我们公司项目上的。所以如果你想拿去用,估计有些东西不需要。比如那个回调函数,或者参数。这个你自己改一下就可以了。可以将回调函数作为一个属性放到opts里。
调用方式:newsky_select('mySelect1',function(){},{oClass:'aa',width:250}),如果你不想写回调函数,可以省掉,不过得改下js,将init:function(obj,callback,opts)里面callback和opts换下位置就可以了。opts里只定了width和class两个属性,width是模拟后的select的宽度。class就是模拟后的select的类了。废话不多说了。上代码:

function sky_select() {
	this.init.apply(this, arguments)
};
sky_select.prototype = {
	init: function(obj, callback, opts) {
		var _this = this,
		o = this.getObj(obj),
		temp = [];
		opts = opts || {};
		this.oOptions = o.options;
		this.current = 0;
		this.n = 0;
		sky_oIndex = 100;
		this.callback = callback;
		this.stopEnter = true;
		this.box = document.createElement('div');
		this.oInput = document.createElement('input');
		this.oItmes = document.createElement('ul');
		var width = opts.width || o.offsetWidth this.box.style.width = width + 'px';
		this.oInput.style.width = width - 7 + 'px';
		this.box.className = opts.oClass || 'select_wrap';
		this.oInput.setAttribute('type', 'text');
		this.oInput.setAttribute('readonly', 'readonly');
		this.oInput.className = 'likeSelect';
		var index = o.options.selectedIndex;
		this.oInput.value = this.oOptions[index || 0].value;
		if (index) this.current = index;
		for (var i = 0,
		len = this.oOptions.length; i < len; i++) {
			temp.push(this.oOptions[i].value)
		};
		this.oItmes.innerHTML = '<li>' + temp.join('</li><li>') + '</li>';
		this.box.appendChild(this.oInput);
		this.box.appendChild(this.oItmes);
		o.parentNode.appendChild(this.box);
		o.style.display = 'none';
		this.item = this.oItmes.getElementsByTagName('li');
		this.oItmes.style.display = 'none';
		this.oInput.onclick = function() {
			_this.show()
		};
		this.oInput.onfocus = function() {};
		this.oInput.onblur = function() {
			this.stopEnter = true;
		};
		this.toSelect(this.item);
		this.hide();
	},
	getObj: function(el) {
		return el = typeof el == 'string' ? document.getElementById(el) : el;
	},
	show: function() {
		var style = this.oItmes.style.display || 'none';
		this.oItmes.style.display = style == 'none' ? 'block': 'none';
		if (style == 'none') this.keyEvent();
		this.item[this.current].className = 'active';
		this.n = this.current;
	},
	toSelect: function(obj) {
		var _this = this;
		for (var i = 0,
		len = obj.length; i < len; i++) { (function(i) {
				obj[i].onclick = function() {
					_this.oInput.value = this.innerHTML;
					_this.oOptions[i].selected = true;
					_this.n = _this.current = i;
					_this.oItmes.style.display = 'none';
					_this.box.style.position = 'static';
					if (_this.callback && typeof _this.callback == 'function') _this.callback();
				};
				obj[i].onmouseover = function() {
					_this.item[_this.current].className = '';
					this.className = 'active';
					_this.n = i;
				}
				obj[i].onmouseout = function() {
					this.className = '';
				}
			})(i);
		};
	},
	keyEvent: function() {
		var _this = this;
		var style = this.oItmes.style.display || 'none';
		if (style == 'none') return;
		this.stopEnter = false;
		this.box.parentNode.style.zIndex = sky_oIndex++;
		this.oItmes.onmouseout = function() {
			_this.item[_this.current].className = 'active';
		};
		document.onkeyup = function(e) {
			e = e || window.event;
			switch (e.keyCode) {
			case 38:
				_this.up();
				break;
			case 40:
				_this.down();
				break;
			case 13:
				_this.enter();
				break;
			default:
				;
			}
		}
	},
	up: function() {
		if (this.n == 0) return;
		this.n--;
		this.item[this.current].className = '';
		this.current = this.n;
		this.item[this.n].className = 'active';
		this.oInput.value = this.item[this.n].innerHTML;
		this.oOptions[this.n].selected = true;
	},
	down: function() {
		if (this.n == this.item.length - 1) return;
		this.n++;
		this.item[this.current].className = '';
		this.current = this.n;
		this.item[this.n].className = 'active';
		this.oInput.value = this.item[this.n].innerHTML;
		this.oOptions[this.n].selected = true;
	},
	enter: function() {
		if (this.stopEnter) return;
		this.oInput.value = this.item[this.n].innerHTML;
		this.oOptions[this.n].selected = true;
		this.current = this.n;
		this.oItmes.style.display = 'none';
		if (this.callback && typeof this.callback == 'function') this.callback();
		this.stopEnter = true;
	},
	hide: function() {
		var _this = this;
		this.addEvent(document, 'click',
		function(e) {
			e = e || window.event;
			var targ = e.target || e.srcElement;
			if (targ != _this.oItmes && targ != _this.oInput) _this.oItmes.style.display = 'none';
		})
	},
	addEvent: function(elm, evType, fn, useCapture) {
		if (elm.addEventListener) {
			elm.addEventListener(evType, fn, useCapture);
			return true;
		} else if (elm.attachEvent) {
			var r = elm.attachEvent('on' + evType, fn);
			return r;
		} else {
			elm['on' + evType] = fn;
		}
	}
}

HTML:

<!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=utf-8" />
<title>无标题文档</title>
<style type="text/css">
* {
	margin:0;
	padding:0;
	font-family:Arial, Helvetica, sans-serif;
	font-size:11px;
}
ul {
	list-style:none;
}
.box {
	margin:10px auto;
	width:250px;
	height:24px;
	position:relative;
}
.aa {
	position:absolute;
	top:0;
	left:0;
}
.likeSelect {
	display:block;
	height:22px;
	line-height:22px;
	background:url(images/icon_select_arrow.gif) no-repeat 100% 8px;
	border:1px solid;
	border-color:#aeaeae #e5e5e5 #e5e5e5;
	padding-left:5px;
	cursor:default;
}
div ul {
	border:1px solid #e5e5e5;
	padding:1px;
	margin-top:-1px;
*margin-top:-2px;
	background:#fff;
}
div ul li {
	height:20px;
	line-height:20px;
	text-decoration:none;
	color:#000;
	display:block;
	padding-left:5px;
	cursor:default;
}
div ul li.active {
	background:#B91F33;
	color:#fff;
}
</style>
<script type="text/javascript" src="myselect.js"></script>
<script type="text/javascript">
window.onload = function(){
var myselect = document.getElementById('mySelect')
new sky_select('mySelect',function(){alert(myselect.options[myselect.options.selectedIndex].value)},{oClass:'aa',width:250})
new sky_select('mySelect1',function(){},{oClass:'aa',width:250})
}
</script>
</head>
<body>
<div class="box">
  <select name="" id="mySelect">
    <option value="default">default</option>
    <option value="options1">options1</option>
    <option value="options2">options2</option>
    <option value="options3" selected="selected">options3</option>
    <option value="options4">options4</option>
    <option value="options5">options5</option>
  </select>
</div>
<div class="box">
  <select name="" id="mySelect1">
    <option value="default">default</option>
    <option value="options1">options1</option>
    <option value="options2">options2</option>
    <option value="options3">options3</option>
    <option value="options4">options4</option>
    <option value="options5">options5</option>
  </select>
</div>
</body>
</html>
注意我这里用到了一个全局变量叫sky_oIndex,这个是为了让弹出的下拉框总是显示在最上面,不过这样也有局限性。如果两个页面的select不在一个层级上这个没用了。哎,我还没想到解决办法,不过目前这样基本上够用了。

另:右边那个小三角自己做一个吧。

posted @ 2010-10-14 15:33  zjhsd2007  阅读(738)  评论(1编辑  收藏  举报