效果地址:
http://search1.taobao.com/browse/ad_search.htm
具体代码见: 附件1
其中关键代码解析:
一、构造类别数组
声明一个类别数组cat
cats['11']=['电脑硬件/台式整机/网络设备','1']; cats['110502']=['品牌液晶显示器','11']; cats['110202']=['内存','11'];
5000多个略…,规则为:
数组的下标是类别id,
第一个元素为类别名
第二个元素为类别父id
接下来构一个将cats数组存入一个parent数组,数组的下标为cats数组的父id,元素为类别数组本身:
for (c in cats) { var ii = cats[c][1]; if (!parent[ii]) { parent[ii] = new Array(); } parent[ii][parent[ii].length] = c; }
这样,形成如下图的两个类别数组:
二、填充下拉框方法
利用cats 和parent两个数组填充,主要是得到了选中的某个类别的子类别集合:
/* id:选中的类别id obj:下拉列表框dom对象 defaultId: 如果要选中默认的某个子,则传递此参数 isFirst:为了可以连级初始化所用。 */ function _addList(id, obj, defaultId, isFirst) { if (!defaultId) { defaultId = -1; } var s = 0; if (haveBlank == 'true') { obj.options[s++] = new Option('', ''); } if (parent[id]) { //利用上面的数组关系直接得到了子数组 for (var i = 0; i < parent[id].length; ++i) { var catId = parent[id][i];//某个子的id if (!parent[catId]) { obj.options[s++] = new Option(cats[catId][0], catId); }else { obj.options[s++] = new Option(cats[catId][0] + ' ->', catId); //如果还有子显示一个"->" } if (defaultId >= 0 && defaultId == catId) { obj.options[s-1].selected = true; changeSubCat(obj); }else if (i == 0 && !isFirst && haveBlank == '') { obj.options[i].selected = true; changeSubCat(obj); } } } }
三、填充下拉框的子下拉框
其中做了一些判断是否有子,是否有子下拉框。
function changeSubCat(obj) { if (!obj || !obj.name) { error('obj not found!'); return; } var name = obj.name; var form = document.forms[formName]; if (!form) { error('form not found!'); return; } var selectNum = -1; for (var i = 0; i < catSel.length; ++i) { if (catSel[i] == name) { selectNum = i; break; } } if (selectNum < 0) { debug('can\'t found sub select'); _setValue(); return; } if (selectNum + 1 >= catSel.length || !form.elements[catSel[selectNum + 1]]) { debug('can\'t found sub select 1'); _setValue(); return; } var subSel = form.elements[catSel[selectNum + 1]]; _clearList(subSel); for (var i = selectNum + 1; i < catSel.length; ++i) { if (form.elements[catSel[i]]) { _clearList(form.elements[catSel[i]]); } } if (obj.options[obj.selectedIndex].value == '') { _setValue(); return; } var catId = obj.options[obj.selectedIndex].value; if (!parent[catId]) { debug('no sub select data'); _setValue(); return; } _addList(catId, subSel); _setValue(); }
如上方法可实现了多级下拉框连动,不过有以下问题:
1. 和form绑定死了
2. 在一个页面无法存在多个连动下拉框
3. 下拉框的name不能自定义,
在项目中同样有此需求,需要同时使用多个连动下拉框,同时name也需自定义,稍改进了一下,将各种方法和数组放入类中,同时根据下拉框的id来绑定下拉框,集成了下拉框的onchagne事件
function TreeSelect(){ this.haveBlank=undefined; this.cats=undefined; this.parent=undefined; /** * 初始化数据 */ this.init= function(_cats,_haveBlank,_selid){ this.cats= _cats; this.initParnet(_cats); this.haveBlank=_haveBlank; this.initSelObj(_selid); }; /** * 初始化select对象数组 */ this.initSelObj=function(_selid){ var p = this; function fireChangeEvent(){ p.changeSubCat(event.srcElement); } this.catSel = _selid.split(','); this.sel_ar = new Array(); for(var i=0;i<this.catSel.length;i++){ this.sel_ar[i] = document.getElementById(this.catSel[i]); this.sel_ar[i].attachEvent('onchange',fireChangeEvent,true); } }; /** * 初始化树数据数组 */ this.initParnet=function(cats){ this.parent = new Array(); for (c in cats) { var ii = cats[c][1]; if (!this.parent[ii]) { this.parent[ii] = new Array(); } this.parent[ii][this.parent[ii].length] = c; } }; /** * 清空select列表 */ this._clearList=function(obj) { if (!obj) { return; } for (var i = obj.length - 1; i >= 0; --i) { obj.remove(i); } obj.value = ''; } ; /** * 改变子的选择 */ this.changeSubCat=function(obj) { if (!obj || !obj.id) { error('obj not found!'); return; } var name = obj.id; var selectNum = -1; for (var i = 0; i < this.catSel.length; ++i) { if (this.catSel[i] == name) { selectNum = i; break; } } if (selectNum < 0) { debug('can\'t found sub select'); return; } if (selectNum + 1 >= this.catSel.length || !document.getElementById( this.catSel[selectNum + 1] )) { debug('can\'t found sub select 1'); return; } var subSel = document.getElementById(this.catSel[selectNum + 1]); this._clearList(subSel); for (var i = selectNum + 1; i < this.catSel.length; ++i) { if (document.getElementById([this.catSel[i]])) { this._clearList(document.getElementById(this.catSel[i])); } } var catId = obj.options[obj.selectedIndex].value; if (!this.parent[catId]) { debug('no sub select data'); return; } this._addList(catId, subSel); }; /** * 填充一个select */ this._addList=function(id, obj, defaultId, isFirst) { if (!defaultId) { defaultId = -1; } var s = 0; if (this.haveBlank == 'true') { obj.options[s++] = new Option('请选择', ''); } if (this.parent[id]) {//当前选中的子数组 for (var i = 0; i < this.parent[id].length; ++i) { var catId = this.parent[id][i]; if (!this.parent[catId]) { obj.options[s++] = new Option(this.cats[catId][0], catId); }else { obj.options[s++] = new Option(this.cats[catId][0] + ' ->', catId); } if (defaultId >= 0 && defaultId == catId) { obj.options[s-1].selected = true; this.changeSubCat(obj); }else if (i == 0 && !isFirst && this.haveBlank == '') { obj.options[i].selected = true; this.changeSubCat(obj); } } } }; } function debug(info) { //alert(info); } function error(info) { alert(info); }
详见: 附件2
实际项目中需要和数据库结合起来,通过标签输出,下面附件内容供大家参考: