js自定义多级联动下拉菜单,实用方便

工作中经常使用这个js自定义多级联动下拉菜单,实用方便

尤其当需要把将数据库中的层级数据转换为树形结构时,还有就是根据条件动态添加减少菜单时


test.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>js自定义多级联动下拉菜单</title>
<script type="text/javascript">
var gt = function (id) {
    return "string" == typeof id ? document.getElementById(id) : id;
};

function addEventHandler(oTarget, sEventType, fnHandler) {
    if (oTarget.addEventListener) {
        oTarget.addEventListener(sEventType, fnHandler, false);
    } else if (oTarget.attachEvent) {
        oTarget.attachEvent("on" + sEventType, fnHandler);
    } else {
        oTarget["on" + sEventType] = fnHandler;
    }
};

function Each(arrList, fun){
    for (var i = 0, len = arrList.length; i < len; i++) { fun(arrList[i], i); }
};

function GetOption(val, txt) {
    var op = document.createElement("OPTION");
    op.value = val; op.innerHTML = txt;
    return op;
};

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

Object.extend = function(destination, source) {
    for (var property in source) {
        destination[property] = source[property];
    }
    return destination;
}


var CascadeSelect = Class.create();
CascadeSelect.prototype = {
  //select集合,菜单对象
  initialize: function(arrSelects, arrMenu, options) {
    if(arrSelects.length <= 0 || arrMenu.lenght <= 0) return;//菜单对象
    
    var oThis = this;
    
    this.Selects = [];//select集合
    this.Menu = arrMenu;//菜单对象
    
    this.SetOptions(options);
    
    this.Default = this.options.Default || [];
    
    this.ShowEmpty = !!this.options.ShowEmpty;
    this.EmptyText = this.options.EmptyText.toString();
    
    //设置Selects集合和change事件
    Each(arrSelects, function(o, i){
        addEventHandler((oThis.Selects[i] = gt(o)), "change", function(){ oThis.Set(i); });
    });
    
    this.ReSet();
  },
  //设置默认属性
  SetOptions: function(options) {
    this.options = { //默认值
        Default:    [], //默认值(按顺序)
        ShowEmpty:    false, //是否显示空值(位于第一个)
        EmptyText:    "请选择" //空值显示文本(ShowEmpty为true时有效)
    };
    Object.extend(this.options, options || {});
  },
  //初始化select
  ReSet: function() {
  
    this.SetSelect(this.Selects[0], this.Menu, this.Default.shift());
    this.Set(0);
  },
  //全部select设置
  Set: function(index) {
    var menu = this.Menu
    
    //第一个select不需要处理所以从1开始
    for(var i=1, len = this.Selects.length; i < len; i++){
        if(menu.length > 0){
            //获取菜单
            var value = this.Selects[i-1].value;
            if(value!=""){
                Each(menu, function(o){ if(o.val == value){ menu = o.menu || []; } });
            } else { menu = []; }
            
            //设置菜单
            if(i > index){ this.SetSelect(this.Selects[i], menu, this.Default.shift()); }
        } else {
            //没有数据
            this.SetSelect(this.Selects[i], [], "");
        }
    }
    //清空默认值
    this.Default.length = 0;
  },
  //select设置
  SetSelect: function(oSel, menu, value) {
    oSel.options.length = 0; oSel.disabled = false;
    if(this.ShowEmpty){ oSel.appendChild(GetOption("", this.EmptyText)); }
    if(menu.length <= 0){ oSel.disabled = true; return; }
    
    Each(menu, function(o){
        var op = GetOption(o.val, o.txt ? o.txt : o.val); op.selected = (value == op.value);
        oSel.appendChild(op);
    });    
  },
  //添加菜单
  Add: function(menu) {
    this.Menu[this.Menu.length] = menu;
    this.ReSet();
  },
  //删除菜单
  Delete: function(index) {
    if(index < 0 || index >= this.Menu.length) return;
    for(var i = index, len = this.Menu.length - 1; i < len; i++){ this.Menu[i] = this.Menu[i + 1]; }
    this.Menu.pop()
    this.ReSet();
  }
};


window.onload=function(){
    
    var menu = [
        {'val': '1', 'txt': 'value'},
        {'val': '2 ->', 'menu': [
            {'val': '2_1'},
            {'val': '2_2'}
        ]},
        {'val': '3 ->', 'menu': [
            {'val': '3_1 ->', 'menu': [
                {'val': '3_1_1'},
                {'val': '3_1_2'}
            ]},
            {'val': '3_2'}
        ]},
        {'val': '4 ->', 'menu': [
            {'val': '4_1 ->', 'menu': [
                {'val': '4_1_1 ->', 'menu': [
                    {'val': '4_1_1_1'}
                ]}
            ]}
        ]}
    ];
    var menu = [{"val":"1","txt":"\u4e9a\u6d32","menu":[{"val":"18","txt":"\u97e9\u56fd","menu":[{"val":"19","txt":"\u9996\u5c14"}]},{"val":"5","txt":"\u4e2d\u56fd","menu":[{"val":"10","txt":"\u4e0a\u6d77"},{"val":"11","txt":"\u5e7f\u5dde"},{"val":"12","txt":"\u6df1\u5733"},{"val":"13","txt":"\u5929\u6d25"},{"val":"9","txt":"\u5317\u4eac","menu":[{"val":"14","txt":"\u671d\u9633\u533a"}]}]}]},{"val":"2","txt":"\u6b27\u6d32","menu":[{"val":"15","txt":"\u82f1\u56fd","menu":[{"val":"16","txt":"\u4f26\u6566"}]},{"val":"6","txt":"\u6cd5\u56fd","menu":[{"val":"17","txt":"\u5df4\u9ece"}]},{"val":"7","txt":"\u5fb7\u56fd","menu":[{"val":"17","txt":"\u5df4\u9ece"}]},{"val":"8","txt":"\u610f\u5927\u5229","menu":[{"val":"17","txt":"\u5df4\u9ece"}]}]},{"val":"3","txt":"\u5317\u7f8e\u6d32","menu":[{"val":"15","txt":"\u82f1\u56fd","menu":[{"val":"16","txt":"\u4f26\u6566"}]},{"val":"6","txt":"\u6cd5\u56fd","menu":[{"val":"17","txt":"\u5df4\u9ece"}]},{"val":"7","txt":"\u5fb7\u56fd","menu":[{"val":"17","txt":"\u5df4\u9ece"}]},{"val":"8","txt":"\u610f\u5927\u5229","menu":[{"val":"17","txt":"\u5df4\u9ece"}]}]},{"val":"4","txt":"\u5357\u7f8e\u6d32","menu":[{"val":"15","txt":"\u82f1\u56fd","menu":[{"val":"16","txt":"\u4f26\u6566"}]},{"val":"6","txt":"\u6cd5\u56fd","menu":[{"val":"17","txt":"\u5df4\u9ece"}]},{"val":"7","txt":"\u5fb7\u56fd","menu":[{"val":"17","txt":"\u5df4\u9ece"}]},{"val":"8","txt":"\u610f\u5927\u5229","menu":[{"val":"17","txt":"\u5df4\u9ece"}]}]}];
    var sel=["sel1", "sel2", "sel3", "sel4", "sel5"];
    
    var val=["3 ->", "3_1 ->", "3_1_2"];
    
    var cs = new CascadeSelect(sel, menu, { Default: val });
    
    gt("btnA").onclick=function(){cs.ShowEmpty=!cs.ShowEmpty;}
    
    gt("btnB").onclick=function(){
        cs.Add(
            {'val': '5 ->', 'menu': [
                {'val': '5_1 ->', 'menu': [
                    {'val': '5_1_1 ->', 'menu': [
                        {'val': '5_1_1_1 ->', 'menu': [
                            {'val': '5_1_1_1_1'}
                        ]}
                    ]}
                ]}
            ]}
        )
    }
    
    gt("btnC").onclick=function(){
        cs.Delete(3)
    }
}
</script>

<style type="text/css">
.sel select{ width:100px;}
</style>

</head>
<body>

<div class="sel">
<select id="sel1"></select>
<select id="sel2"></select>
<select id="sel3"></select>
<select id="sel4"></select>
<select id="sel5"></select>
</div>
<br />
<div>
<input id="btnA" type="button" value="显示/不显示空值" />
<input id="btnB" type="button" value="添加菜单" />
<input id="btnC" type="button" value="减少菜单" />

</div>
</body>
</html>


将层级数据处理树形 tree.php

<?php
//递归形式
function create_tree($arr,$pid=0) {
	$jshtml="";
	$ret = array();
	foreach($arr as $k => $v) {
		if($v['pid'] == $pid) {
			$tmp[val] = $v[id];
			$tmp[txt] = $v[title];
			unset($arr[$k]);
			$children=$this->create_tree($arr,$v['id']);
			!empty($children) && $tmp['menu'] =$children; 
			$ret[] = $tmp;
			//$ret[jshtml]= 'dsy.add("0_'.$pid.'",['.rtrim($jshtml,',').']'; 
		}
	}
	return $ret;
}



用到的表及测试数据 it_country.sql

-- phpMyAdmin SQL Dump
-- version 3.3.10
-- http://www.phpmyadmin.net
--
-- 主机: 127.0.0.1
-- 生成日期: 2014 年 06 月 12 日 13:53
-- 服务器版本: 5.5.36
-- PHP 版本: 5.3.28

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- 数据库: `itour`
--

-- --------------------------------------------------------

--
-- 表的结构 `ih_t_country`
--

CREATE TABLE IF NOT EXISTS `it_country` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '分类ID',
  `depth` tinyint(11) NOT NULL DEFAULT '0' COMMENT '深度',
  `path` varchar(255) NOT NULL,
  `name` varchar(30) NOT NULL COMMENT '标志',
  `title` varchar(50) NOT NULL COMMENT '标题',
  `pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '上级分类ID',
  `sort` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '排序(同级有效)',
  `list_row` tinyint(3) unsigned NOT NULL DEFAULT '10' COMMENT '列表每页行数',
  `create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
  `update_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
  `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '数据状态',
  `icon` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '分类图标',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_name` (`name`),
  KEY `pid` (`pid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='分类表' AUTO_INCREMENT=20 ;

--
-- 转存表中的数据 `ih_t_country`
--

INSERT INTO `it_country` (`id`, `depth`, `path`, `name`, `title`, `pid`, `sort`, `list_row`, `create_time`, `update_time`, `status`, `icon`) VALUES
(1, 0, ',1,', 'yazhou', '亚洲', 0, 0, 10, 0, 0, 1, 0),
(2, 0, ',2,', 'europe', '欧洲', 0, 0, 10, 0, 0, 1, 0),
(3, 0, ',3,', 'North America', '北美洲', 0, 0, 10, 0, 0, 1, 0),
(4, 0, ',4,', 'South America', '南美洲', 0, 0, 10, 0, 0, 1, 0),
(5, 1, ',1,5,', 'china', '中国', 1, 0, 10, 0, 0, 1, 0),
(6, 1, ',2,6,', 'France', '法国', 2, 0, 10, 0, 0, 1, 17),
(7, 1, ',2,7,', 'Germany', '德国', 2, 0, 10, 0, 0, 1, 19),
(8, 1, ',2,8,', 'Italy', '意大利', 2, 0, 10, 0, 0, 1, 20),
(9, 2, ',1,5,9,', 'beijing', '北京', 5, 0, 10, 0, 0, 1, 0),
(10, 2, ',1,5,10,', 'shanghai', '上海', 5, 0, 10, 0, 0, 1, 0),
(11, 2, ',1,5,11,', 'guangzhou', '广州', 5, 0, 10, 0, 0, 1, 0),
(12, 2, ',1,5,12,', 'shenzhen', '深圳', 5, 0, 10, 0, 0, 1, 0),
(13, 2, ',1,5,13,', 'tianjin', '天津', 5, 0, 10, 0, 0, 1, 0),
(14, 3, ',1,5,9,14,', 'dd', '朝阳区', 9, 0, 10, 0, 0, 1, 0),
(15, 1, ',2,15,', 'yingguo', '英国', 2, 0, 10, 0, 0, 1, 0),
(16, 2, ',2,15,16,', 'lundun', '伦敦', 15, 0, 10, 0, 0, 1, 0),
(17, 2, ',2,6,17,', 'bali', '巴黎', 6, 0, 10, 0, 0, 1, 0),
(18, 1, ',1,18,', '', '韩国', 1, 0, 10, 0, 0, 1, 0),
(19, 2, ',1,18,19,', '订单', '首尔', 18, 0, 10, 0, 0, 1, 0);





你可能感兴趣的:(ji级联)