纯JS实现页面select转换为combox控制,支持键盘控制和联想
使用方法:
1.直接在select上添加combox样式
2.使用new combox(obj).transform()将obj转换为combox,obj必须要是select
注意事项:
转换过的combox可以通过原来select的relatedCombox关联找到,需要销毁转换的combox还原原来的select话使用obj.relatedCombox.destroy(),当combox值发生变化后,会激发原select的onchange事件
代码如下

Code

/**//**
* combox控件
*
* @author:xueduanyang
*/

<!-- /**//*
/**
* combox控件 xueduanyang 2009.1.5 使用方法,在页面引用combox.css和combox.js
* 直接在页面的select元素上加上combox样式即可,不区分大小写,自动将页面的select转换成为combox
* 支持键盘上下选择,下拉菜单滚动条自动适应,完美模拟select功能 支持联想 无JS污染,使用方便,功能便捷
* 适用范围,页面的select转换,对于小于1W条以下的select数据完全没有问题,对于数据量过大的select或者ajax远程读取的数据需要重构
*/

function combox(el)
{
// 保存select引用指针
this.select = el;
el.relatedCombox = this;
// 得到select的高度等
var t = el.offsetTop;
var l = el.offsetLeft;
var w = el.offsetWidth;
var h = el.offsetHeight - 2;

while (el = el.offsetParent)
{
t += el.offsetTop;
l += el.offsetLeft;
}
this.top = t;
this.left = l;
this.width = w;
this.height = h;
this.selectRow = null;
this.minWidth = 200;
// 关联combox和select

this.FnRelateComboxWithSelect = function()
{
}
}
// 创建输入框

combox.prototype.createTextBox = function()
{
var span = document.createElement('span');
this.inptContainer = span;
var width = this.minWidth ? (this.width < this.minWidth
? this.width
: this.minWidth) : this.width + "px";
span.className = 'combox_input';
span.style.height = this.height + "px";
span.style.width = width;
var txtBox = document.createElement('input');
this.txtBox = txtBox;
txtBox.type = 'text';
txtBox.setAttribute('autoComplete', 'off');
txtBox.id = 'combox_transform_select_'
+ (this.select.id ? this.select.id : this.select.name);
txtBox.value = this.select.options[this.select.selectedIndex].text;
txtBox.className = 'combox_text';
txtBox.style.width = width - 18 + "px";
txtBox.style.height = this.height - 2 + "px";
span.appendChild(txtBox);
this.select.parentNode.insertBefore(span, this.select);
var block = document.createElement('span');
this.block = block;
block.style.width = "16px";
block.style.cursor = 'hand';
block.innerHTML = '◢';
this.dpListBtn = block;
span.appendChild(block);
}
// 创建下拉框

combox.prototype.createDpList = function()
{
var select = this.select;
var txtBox = this.txtBox;
var selectRow = this.selectRow;
//
var container = document.createElement("div");
this.dpListContainer = container;
container.style.display = 'none';
container.style.position = "absolute";
container.style.width = this.width + "px";
container.style.top = (this.top + this.height) + 1 + "px";
container.style.left = this.left + "px";
container.className = 'combox_container';
container.innerHTML = '<iframe style="position:absolute;z-index:-1;width:100%;height:100%;top:0;left:0;right:0;scrolling:no;" frameborder="0" src="about:blank"></iframe>';
//
document.body.appendChild(container);
// 列表
var dpList = document.createElement("ul");
this.dpListContainer.dpList = dpList;
dpList.className = 'combox_dplist';
container.appendChild(dpList);
// 列表每行

for (var i = 0; i < select.options.length; i++)
{
var row = document.createElement("li");
row.className = 'combox_row';
row.innerHTML = select.options[i].text;
row.selectValue = select.options[i].value;
row.index = i;
//

if (select.options[i].selected == true)
{
selectRow = row;
}
//
dpList.appendChild(row);
}

if (selectRow == null)
{
selectRow = dpList.childNodes[0];
}

container.onmouseover = function()
{
var el = document.all ? window.event.srcElement : arguments[0].target;

if (el.tagName && el.tagName == 'LI')
{
selectRow.className = 'combox_row_mouseout';
el.className = 'combox_row_mouseover';
selectRow = el;
}
}

container.onclick = function()
{
var el = document.all ? window.event.srcElement : arguments[0].target;

if (el.tagName && el.tagName == 'LI')
{
selectRow = el;
txtBox.value = el.innerHTML;

if (select.value != el.selectValue)
{

if (el.selectValue == null || el.selectValue == '')
{

for (var i = 0; i > select.options.length; i++)
{

if (select.options[i].value == el.selectValue)
{
select.options[i].selected = true;
break;
}
}
select.options[0].selected = true;
} else
select.value = el.selectValue;
if (select.onchange)
select.onchange(select);
}
// 同时我们把下拉的关闭掉。
container.style.display = 'none';
stopEventPropagation();
}
}

this.txtBox.onkeydown = function()
{
var keyCode = window.event
? window.event.keyCode
: arguments[0].keyCode;
// down

if (keyCode == 40 && container.style.display != 'none')
{
var selectRowHeight = 0;

for (var i = 0; i < dpList.childNodes.length; i++)
{
var row = dpList.childNodes[i];


if (selectRow.index >= i)
{

if (row.style.display != 'none')
{
selectRowHeight += 20;
}

} else
{

if (row.style.display != 'none')
{
selectRow.className = 'combox_row_mouseout';
selectRow = row;
row.className = 'combox_row_mouseover';
break;
}
}
}
keyDownMoveScrollTop(keyCode, selectRowHeight);
}// up

else if (keyCode == 38 && container.style.display != 'none')
{

if (selectRow.index > 0)
{
var selectRowHeight = 0;
var find = false;

for (var i = selectRow.index - 1; i >= 0; i--)
{
var row = dpList.childNodes[i];

if (row.style.display != 'none')
{
selectRowHeight += 20;

if (!find)
{
selectRow.className = 'combox_row_mouseout';
selectRow = row;
row.className = 'combox_row_mouseover';

find = true;
}
}
}
}
keyDownMoveScrollTop(keyCode, selectRowHeight - 20);
}
}

this.txtBox.onkeyup = function()
{
var keyCode = window.event
? window.event.keyCode
: arguments[0].keyCode;

if (keyCode == 40 || keyCode == 38)
{

if (selectRow != null)
{
selectRow.className = 'combox_row_mouseover';

if (container.style.display == 'none')
{
container.style.display = '';
resetContainerHeight();
resetContainerHeight();
}
}
return false;
} // enter

else if (keyCode == 13)
{

if (container.style.display != 'none')
{
txtBox.value = selectRow.innerHTML;

if (select.value != selectRow.selectValue)
{
if (selectRow.selectValue == null

|| selectRow.selectValue == '')
{

for (var i = 0; i > select.options.length; i++)
{

if (select.options[i].value = selectRow.selectValue)
{
select.options[i].selected = true;
break;
}
}
} else
select.value = selectRow.selectValue;
if (select.onchange)
select.onchange(select);
}
container.style.display = 'none';
stopEventPropagation();
return false;

} else
{

for (var i = 0; i < dpList.childNodes.length; i++)
{
var row = dpList.childNodes[i];
row.style.display = '';
row.className = 'combox_row_mouseout';
}
container.style.display = '';
selectRow.className = 'combox_row_mouseover';
resetContainerHeight();
resetContainerHeight();
stopEventPropagation();
return false;
}
}// esc

else if (keyCode == 27)
{

if (container.style.display != 'none')
{
container.style.display = 'none';
return false;

} else
{
return false;
}
}// page down

else if (keyCode == 34)
{

for (var i = 0; i < dpList.childNodes.length; i++)
{
var row = dpList.childNodes[i];
row.style.display = '';
row.className = 'combox_row_mouseout';
}
container.style.display = '';
selectRow.className = 'combox_row_mouseover';
resetContainerHeight();
resetContainerHeight();
return false;

} else
{
var val = this.value;

for (var i = 0, row; row = dpList.childNodes[i]; i++)
{

if (row.innerHTML.indexOf(val) > -1)
{
row.style.display = '';

} else
{
row.style.display = 'none';
}
}
resetContainerHeight();
}
if (selectRow != null)
selectRow.className = 'combox_row_mouseover';
container.style.display = '';
}
// this.txtBox.onfocus = function() {
// if (container.style.display != 'none') {
// container.style.display = 'none';
// }
// }
// this.txtBox.onblur = function() {
// var el = document.all ? window.event.srcElement : arguments[0].target;
// if (el == container) {
// return false;
// }
// finishComboxInput();
//
// }

this.txtBox.onclick = function()
{
stopEventPropagation();
}

this.dpListBtn.onclick = function()
{
resetRowDisplay();

if (container.style.display == 'none')
{
container.style.display = '';

} else
{

for (var i = 0; i < select.options.length; i++)
{

if (select.options[i].text == txtBox.value)
{

if (select.options[i].selected != true)
{
select.options[i].selected = true;
if (select.onchange)
select.onchange(select);
}
break;
}
if (i == select.options.length - 1)
txtBox.value = select.options[select.selectedIndex].text;
}

for (var i = 0; i < dpList.childNodes.length; i++)
{
var row = dpList.childNodes[i];

if (row.innerHTML == txtBox.value)
{
selectRow.className = 'combox_row_mouseout';
selectRow = row;
row.className = 'combox_row_mouseover';
break;
}
}
container.style.display = 'none'
}
resetContainerHeight();
resetContainerHeight();
stopEventPropagation();
}

function finishComboxInput()
{
// 键盘或者鼠标选中的

try
{

if (txtBox.value == selectRow.innerHTML)
{

if (select.value != selectRow.selectValue)
{
if (selectRow.selectValue == null

|| selectRow.selectValue == '')
{

for (var i = 0; i > select.options.length; i++)
{

if (select.options[i].value = selectRow.selectValue)
{
select.options[i].selected = true;
break;
}
}
} else
select.value = selectRow.selectValue;
if (select.onchange)
select.onchange(select);
}

} else
{
// 按键后,鼠标选中

if (select.value != selectRow.selectValue)
{
txtBox.value = selectRow.innerHTML;
if (selectRow.selectValue == null

|| selectRow.selectValue == '')
{

for (var i = 0; i > select.options.length; i++)
{

if (select.options[i].value = selectRow.selectValue)
{
select.options[i].selected = true;
break;
}
}
} else
select.value = selectRow.selectValue;
if (select.onchange)
select.onchange(select);

} else
{// 手输

for (var i = 0; i < select.options.length; i++)
{

if (select.options[i].text == txtBox.value)
{

if (select.options[i].selected != true)
{
select.value = select.options[i].value;
if (select.onchange)
select.onchange(select);
}
break;
}
if (i == (select.options.length - 1))
txtBox.value = select.options[select.selectedIndex].text;
}

for (var i = 0; i < dpList.childNodes.length; i++)
{
var row = dpList.childNodes[i];

if (row.innerHTML == txtBox.value)
{
if (selectRow != null)
selectRow.className = 'combox_row_mouseout';
selectRow = row;
row.className = 'combox_row_mouseover';
break;
}
}
}
}
container.style.display = 'none';

} catch (e)
{
alert(e)
}
}

if (document.addEventListener)
{
document.body.addEventListener('click', finishComboxInput, false);

} else
{
document.body.attachEvent('onclick', finishComboxInput);// IE
}

function resetRowDisplay()
{
var f = true;

for (var i = 0, row; row = dpList.childNodes[i]; i++)
{
row.style.display = '';
row.className = 'combox_row_mouseout';
selectRow.className = 'combox_row_mouseover';
}
}
// 控制容器的最大高度

function resetContainerHeight()
{
var minHeight = 0;
var selectRowTop = 0;
var curRowIsSelected = false;

for (var i = 0; i < dpList.childNodes.length; i++)
{
var row = dpList.childNodes[i];

if (row.style.display != 'none')
{
minHeight += 20;

if (!curRowIsSelected)
{

if (selectRow != row)
{
selectRowTop += 20;

} else
{
curRowIsSelected = true;
}
}
}
}

if (minHeight < 200)
{
container.style.height = minHeight == 0 ? 20 + 2 + "px" : minHeight
+ 2 + "px";

} else
{
container.style.height = 202 + "px";

if (container.style.display == 'none')
{
}

if (selectRow != null && selectRow.style.display != 'none')
{
container.scrollTop += selectRowTop - container.scrollTop;

} else
{
container.scrollTop = 0;
}
}
}

function keyDownMoveScrollTop(keyCode, selectRowHeight)
{
// down

if (keyCode == 40 && container.style.display != 'none')
{
if (selectRowHeight - container.scrollTop > 180)
container.scrollTop += 20;
}// up

else if (keyCode == 38 && container.style.display != 'none')
{
if (selectRowHeight < container.scrollTop)
container.scrollTop -= 20;
}
}
// 阻止事件传播

function stopEventPropagation()
{
var event = window.event
? window.event
: arguments.callee.caller.arguments[0];
event.cancelBubble = true;
event.returnValue = false;

if (event.preventDefault)
{
event.preventDefault();
}

if (event.stopPropagation)
{
event.stopPropagation();
}
}
}

combox.prototype.correctErrData = function()
{
//
}

combox.prototype.hideDropList = function()
{
this.dpListContainer.style.display = 'none';
}

combox.prototype.transform = function()
{
// 将原select隐藏

this.FnRelateComboxWithSelect = function()
{
var key = document.all
? window.event.propertyName
: arguments[0].attrName;

if (key == 'value')
{
var el = document.all
? window.event.srcElement
: arguments[0].target;
if (el.tagName && el.tagName == 'SELECT'

&& el.relatedCombox != null)
{
el.relatedCombox.txtBox.value = el.options[el.selectedIndex].text;
}
}
// document.getElementById('combox_transform_select_'
// + (p.id ? p.id : p.name)).value = p.options[p.selectedIndex].text;
}

if (document.addEventListener)
{
this.select.addEventListener('DOMAttrModified',
this.FnRelateComboxWithSelect, false);

} else
{
this.select.attachEvent('onpropertychange',
this.FnRelateComboxWithSelect);// IE
}
// 在原select前面新建一个span,里面套一个text
this.createTextBox();
// 下拉列表容器
this.createDpList();
this.correctErrData();
this.select.style.display = 'none';
}

combox.prototype.isDataCorrect = function()
{
return this.txtBox.value == this.select.value;
};
// go go 初始化

(function()
{

function select_transform()
{
var sel_ary = document.getElementsByTagName('select');

for (var i = 0; i < sel_ary.length; i++)
{

if (!sel_ary[i].multiple && sel_ary[i].style.display != 'none')
{
if (hasCss('combox', sel_ary[i].className))
(new combox(sel_ary[i])).transform();
}
}
}

function hasCss(cssName, cssNameAry)
{
var cssAry = cssNameAry.split(/\s/);

for (var i = 0, css; css = cssAry[i]; i++)
{

if (cssName.toLowerCase() == css.toLowerCase())
{
return true;
}
}
return false;
}

if (document.addEventListener)
{
window.addEventListener("load", select_transform, false);// FireFox

} else
{
window.attachEvent("onload", select_transform);// IE
}
})();

combox.prototype.destroy = function()
{


if (document.addEventListener)
{
this.select.removeEventListener('DOMAttrModified',
this.FnRelateComboxWithSelect, false);

} else
{
this.select.detachEvent('onpropertychange',
this.FnRelateComboxWithSelect);// IE
}

if (document.all)
{
this.dpListContainer.removeNode(true);
} else
this.dpListContainer.parentNode.removeChild(this.dpListContainer);

if (document.all)
{
this.inptContainer.removeNode(true);
} else
this.inptContainer.parentNode.removeChild(this.inptContainer);
this.FnRelateComboxWithSelect = null;
this.select.relatedCombox = null;
this.top = null;
this.left = null;
this.height = null;
this.width = null;
this.selectRow = null;
this.select.style.display = '';
this.select = null;

}
<!-- */

<!--.combox_input
{border:1px solid gray;background-color:white;}.combox_text
{vertical-align:middle;position:relative;border:none;}

<!--.combox_container
{background:white;border:1px solid silver;overflow:auto}

<!--.combox_dpList
{list-style:none;margin:0;padding:0;background-color:#fff}

<!--.combox_row
{text-indent:4px;height:20px;line-height:20px;font-size:12px;margin:0;padding:0;}

<!--.combox_row_mouseover
{background-color:gray;color:white;text-indent:4px;height:20px;line-height:20px;font-size:12px;}

<!--.combox_row_mouseout
{background-color:white;color:black;text-indent:4px;height:20px;line-height:20px;font-size:12px;}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!