js面向对象封装级联下拉菜单列表

使用实例中封装好的插件,只需要有一个input元素,即可通过插件自动生成级联下拉菜单,html代码如下所示:

<div style="margin-top:100px;text-align:center;"><input type="text" id="input"></div>

接下来看下具体封装的js代码怎么实现。

1. 声明级联菜单的构造函数

构造函数需要传入一个文本框元素和菜单关联数据两个参数。

//elem为文本框,data为菜单关联数据function CascadeMenu(elem,data){

  }

2. 在构造函数中创建级联菜单相关元素,并放到页面中,具体代码如下:

function CascadeMenu(elem,data){

    //获取文本框this.eInput = elem;

    //设置文本框为只读this.eInput.setAttribute('readonly',true);

    //设置文本框提示this.eInput.placeholder = '请选择';

    //获取文本框父元素vareInputParent =this.eInput.parentNode;

    //创建级联菜单容器this.eCascade = document.createElement('div');

    this.eCascade.className = 'cascade_container';

    //创建菜单下拉列表容器this.eCascadeInto = document.createElement('div');

    this.eCascadeInto.className = 'cascade_into';

    //下拉列表容器默认隐藏this.eCascadeInto.style.display = 'none';

    //将各个元素放到页面中this.eCascade.appendChild(this.eInput);

    this.eCascade.appendChild(this.eCascadeInto);

    eInputParent.appendChild(this.eCascade);

    //获取菜单数据this.aData = data;

    //记录已选择的菜单数据this.aSelected = [];

    //菜单打开状态,默认为false,表示隐藏this.bShow =false;

  }

3. 在文本框上绑定点击事件,生成级联下拉菜单

刚才已经把需要的元素都放到了页面中,现在可以通过点击文本框显示和隐藏级联菜单元素;

在显示级联菜单元素时,应该要通过数据生成级联下拉菜单。

因为每次点击都需要生成,所以可以在构造函数的原型上添加一个方法。如下所示:

function CascadeMenu(elem,data){

    /*…*/this.eInput.addEventListener('click',()=>{

      //判断菜单打开状态if(this.bShow){

        //如果已打开,则隐藏菜单this.eCascadeInto.style.display = 'none';

        //修改菜单打开状态this.bShow =false;

      }else{

        //显示级联菜单元素this.eCascadeInto.style.display = 'none';

        //保存已选择的菜单数据this.aSelected =this.eInput.value.split('>');

        //生成级联菜单this.generateMenu();

      }

    });

  }

  //根据数据生成级联菜单CascadeMenu.prototype.generateMenu =function(){

    //在fnCreatHTML调用实例对象需要声明一个变量指向thisvar_self =this;

    //因为不确定子菜单有多少组,所以需要声明一个函数来递归调用//data:传入数据,step:当前级别function fnCreatHTML(data,step){

      //用于存储子菜单数据varaChildArr =null;

      //生成菜单DOM的字符串varsHTML = '

';

      //循环数据for(let i=0;i

        //判断如果有子菜单,添加child的class,用于显示菜单右侧箭头if(data[i].child){

          //判断是否是当前选择,如果是,加上cur class,并且存储子菜单数据if(data[i].name==this.aSelected[step]){

            aChildArr = data[i].child;

            sHTML += '

';

          }else{

            sHTML += '

';

          }

        }else{

          //如果没有子菜单,直接加到菜单列表中sHTML += data[i].name ==this.aSelected[step]?                                  '

':

                                  '

';

        }

        //添加菜单名称sHTML += data[i].name;

        //结束当前菜单sHTML += '';

      }

      sHTML += '';

      //如果已选择多个菜单,递归调用函数,生成子菜单if(this.aSelected.length>step+1){

        sHTML += fnCreatHTML(aChildArr,step+1);

      }

      return sHTML;

    }

    this.eCascadeInto.innerHTML = fnCreatHTML(this.aData,0);

  }

4. 菜单上绑定事件,用于选择菜单

级联菜单有两种类型,一种是有下级菜单的,点击时显示下级菜单;

一种是没有下级菜单的,点击时直接选择菜单并在文本框中按级别显示所选择的菜单。代码如下所示:

function CascadeMenu(elem,data){

    /*…*///利用事件委托选择菜单this.eCascadeInto.addEventListener('click',(event)=>{

      //获取菜单vareTarget = event.target;

      //获取选择的级别varpo = +eTarget.dataset.po;

      //删除当前选择级后面的数据this.aSelected.splice(po+1,this.aSelected.length-(po+1));

      //修改当前选择数据this.aSelected[po] = eTarget.innerHTML;

      //判断是否有子菜单if(eTarget.className.indexOf('child')==-1){//没有子菜单直接选择this.eInput.value =this.aSelected.join('>');

        this.eCascadeInto.style.display = 'none';

        this.bShow =false;

      }else{//有子菜单显示下一级//重新生成DOM元素,数组中增加空字符串用于显示下一级this.aSelected.push('')

        //重新生成级联菜单this.generateMenu();

      } 

    });

  }

5. 在页面空白处点击时,隐藏菜单

现在只能在文本框上点击显示和隐藏菜单。一般来说任何打开的弹框,都希望在弹框以外的位置可以关闭掉。这样需要修改一下文本框上的点击事件函数:当打开菜单时,要在document元素上绑定点击事件,用于关闭菜单;当隐藏菜单时,需要取消document上绑定的点击事件。如下所示:

正在上传... 取消

function CascadeMenu(elem,data){

    /*…*/this.eInput.addEventListener('click',()=>{

      //判断菜单打开状态if(this.bShow){

        //如果已打开,则隐藏菜单this.eCascadeInto.style.display = 'none';

        //修改菜单打开状态this.bShow =false;

        //取消document上的事件document.onclick =null;

      }else{

        //显示级联菜单元素this.eCascadeInto.style.display = 'none';

        //保存已选择的菜单数据this.aSelected =this.eInput.value.split('>');

        //生成级联菜单this.generateMenu();

        document.onclick = () => {

          //隐藏菜单this.eCascadeInto.style.display = 'none';

          //修改菜单打开状态this.bShow =false;

          //取消document上的事件document.onclick =null;

        }

      }

    });

    //阻止冒泡this.eCascade.addEventListener('click',(event)=>{

      event.stopPropagation();

    });

    /*…*/  }

正在上传... 取消

6. 最后,准备好数据,调用构造函数,生成级联下拉菜单,如下所示:

正在上传... 取消

varjson = [

    {

      "name":"北京市","id":"110000","child":[

        {"name":"市辖区","id":"110100","child":[

          {"name":"东城区","id":"110101","child":null},{"name":"西城区","id":"110102","child":null},{"name":"朝阳区","id":"110105","child":null},{"name":"丰台区","id":"110106","child":null},{"name":"石景山区","id":"110107","child":null},{"name":"海淀区","id":"110108","child":null},{"name":"门头沟区","id":"110109","child":null},{"name":"房山区","id":"110111","child":null},{"name":"通州区","id":"110112","child":null},{"name":"顺义区","id":"110113","child":null},{"name":"昌平区","id":"110114","child":null},{"name":"大兴区","id":"110115","child":null},{"name":"怀柔区","id":"110116","child":null},{"name":"平谷区","id":"110117","child":null},{"name":"密云区","id":"110118","child":null},{"name":"延庆区","id":"110119","child":null}]

        },

        {"name":"北京市","id":"110000","child":null}

      ]

    },

    {

      "name":"河北省","id":"130000","child":[

        {"name":"石家庄市","id":"130100","child":[

          {"name":"市辖区","id":"130101","child":null},{"name":"长安区","id":"130102","child":null},{"name":"桥西区","id":"130104","child":null},{"name":"新华区","id":"130105","child":null},{"name":"井陉矿区","id":"130107","child":null},{"name":"裕华区","id":"130108","child":null},{"name":"藁城区","id":"130109","child":null},{"name":"鹿泉区","id":"130110","child":null},{"name":"栾城区","id":"130111","child":null},{"name":"井陉县","id":"130121","child":null},{"name":"正定县","id":"130123","child":null},{"name":"行唐县","id":"130125","child":null},{"name":"灵寿县","id":"130126","child":null},{"name":"高邑县","id":"130127","child":null},{"name":"深泽县","id":"130128","child":null},{"name":"赞皇县","id":"130129","child":null},{"name":"无极县","id":"130130","child":null},{"name":"平山县","id":"130131","child":null},{"name":"元氏县","id":"130132","child":null},{"name":"赵县","id":"130133","child":null},{"name":"晋州市","id":"130183","child":null},{"name":"新乐市","id":"130184","child":null}]

        },

        {"name":"唐山市","id":"130200","child":[

          {"name":"市辖区","id":"130201","child":null},{"name":"路南区","id":"130202","child":null},{"name":"路北区","id":"130203","child":null},{"name":"古冶区","id":"130204","child":null},{"name":"开平区","id":"130205","child":null},{"name":"丰南区","id":"130207","child":null},{"name":"丰润区","id":"130208","child":null},{"name":"曹妃甸区","id":"130209","child":null},{"name":"滦县","id":"130223","child":null},{"name":"滦南县","id":"130224","child":null},{"name":"乐亭县","id":"130225","child":null},{"name":"迁西县","id":"130227","child":null},{"name":"玉田县","id":"130229","child":null},{"name":"遵化市","id":"130281","child":null},{"name":"迁安市","id":"130283","child":null}]

        },

        {"name":"秦皇岛市","id":"130300","child":[

          {"name":"市辖区","id":"130301","child":null},{"name":"海港区","id":"130302","child":null},{"name":"山海关区","id":"130303","child":null},{"name":"北戴河区","id":"130304","child":null},{"name":"抚宁区","id":"130306","child":null},{"name":"青龙满族自治县","id":"130321","child":null},{"name":"昌黎县","id":"130322","child":null},{"name":"卢龙县","id":"130324","child":null}]

        },

        {"name":"邯郸市","id":"130400","child":[

          {"name":"市辖区","id":"130401","child":null},{"name":"邯山区","id":"130402","child":null},{"name":"丛台区","id":"130403","child":null},{"name":"复兴区","id":"130404","child":null},{"name":"峰峰矿区","id":"130406","child":null},{"name":"邯郸县","id":"130421","child":null},{"name":"临漳县","id":"130423","child":null},{"name":"成安县","id":"130424","child":null},{"name":"大名县","id":"130425","child":null},{"name":"涉县","id":"130426","child":null},{"name":"磁县","id":"130427","child":null},{"name":"肥乡县","id":"130428","child":null},{"name":"永年县","id":"130429","child":null},{"name":"邱县","id":"130430","child":null},{"name":"鸡泽县","id":"130431","child":null},{"name":"广平县","id":"130432","child":null},{"name":"馆陶县","id":"130433","child":null},{"name":"魏县","id":"130434","child":null},{"name":"曲周县","id":"130435","child":null},{"name":"武安市","id":"130481","child":null}]

        }

      ]

    },

    {

      "name":"湖南省","id":"430000","child":[

        {"name":"长沙市","id":"430100","child":[

          {"name":"市辖区","id":"430101","child":null},{"name":"芙蓉区","id":"430102","child":null},{"name":"天心区","id":"430103","child":null},{"name":"岳麓区","id":"430104","child":null},{"name":"开福区","id":"430105","child":null},{"name":"雨花区","id":"430111","child":null},{"name":"望城区","id":"430112","child":null},{"name":"长沙县","id":"430121","child":null},{"name":"宁乡县","id":"430124","child":null},{"name":"浏阳市","id":"430181","child":null}]

        },

        {"name":"株洲市","id":"430200","child":[

          {"name":"市辖区","id":"430201","child":null},{"name":"荷塘区","id":"430202","child":null},{"name":"芦淞区","id":"430203","child":null},{"name":"石峰区","id":"430204","child":null},{"name":"天元区","id":"430211","child":null},{"name":"株洲县","id":"430221","child":null},{"name":"攸县","id":"430223","child":null},{"name":"茶陵县","id":"430224","child":null},{"name":"炎陵县","id":"430225","child":null},{"name":"醴陵市","id":"430281","child":null}]

        },

        {"name":"湘潭市","id":"430300","child":[

          {"name":"市辖区","id":"430301","child":null},{"name":"雨湖区","id":"430302","child":null},{"name":"岳塘区","id":"430304","child":null},{"name":"湘潭县","id":"430321","child":null},{"name":"湘乡市","id":"430381","child":null},{"name":"韶山市","id":"430382","child":null}]

        },

        {"name":"衡阳市","id":"430400","child":[

          {"name":"市辖区","id":"430401","child":null},{"name":"珠晖区","id":"430405","child":null},{"name":"雁峰区","id":"430406","child":null},{"name":"石鼓区","id":"430407","child":null},{"name":"蒸湘区","id":"430408","child":null},{"name":"南岳区","id":"430412","child":null},{"name":"衡阳县","id":"430421","child":null},{"name":"衡南县","id":"430422","child":[

            {"name":"三塘镇",id:"430422",child:null},{"name":"车江镇",id:"430422",child:null}

          ]},{"name":"衡山县","id":"430423","child":null},{"name":"衡东县","id":"430424","child":null},{"name":"祁东县","id":"430426","child":null},{"name":"耒阳市","id":"430481","child":null},{"name":"常宁市","id":"430482","child":null}]

        }

      ]

    },

    {

      "name":"广东省","id":"440000","child":[

        {"name":"广州市","id":"440100","child":[

          {"name":"市辖区","id":"440101","child":null},{"name":"荔湾区","id":"440103","child":null},{"name":"越秀区","id":"440104","child":null},{"name":"海珠区","id":"440105","child":null},{"name":"天河区","id":"440106","child":null},{"name":"白云区","id":"440111","child":null},{"name":"黄埔区","id":"440112","child":null},{"name":"番禺区","id":"440113","child":null},{"name":"花都区","id":"440114","child":null},{"name":"南沙区","id":"440115","child":null},{"name":"从化区","id":"440117","child":null},{"name":"增城区","id":"440118","child":null}]

        },

        {"name":"韶关市","id":"440200","child":[

          {"name":"市辖区","id":"440201","child":null},{"name":"武江区","id":"440203","child":null},{"name":"浈江区","id":"440204","child":null},{"name":"曲江区","id":"440205","child":null},{"name":"始兴县","id":"440222","child":null},{"name":"仁化县","id":"440224","child":null},{"name":"翁源县","id":"440229","child":null},{"name":"乳源瑶族自治县","id":"440232","child":null},{"name":"新丰县","id":"440233","child":null},{"name":"乐昌市","id":"440281","child":null},{"name":"南雄市","id":"440282","child":null}]

        },

        {"name":"深圳市","id":"440300","child":[

          {"name":"市辖区","id":"440301","child":null},{"name":"罗湖区","id":"440303","child":null},{"name":"福田区","id":"440304","child":null},{"name":"南山区","id":"440305","child":null},{"name":"宝安区","id":"440306","child":null},{"name":"龙岗区","id":"440307","child":null},{"name":"盐田区","id":"440308","child":null}]

        },

        {"name":"珠海市","id":"440400","child":[

          {"name":"市辖区","id":"440401","child":null},{"name":"香洲区","id":"440402","child":null},{"name":"斗门区","id":"440403","child":null},{"name":"金湾区","id":"440404","child":null}]

        }

      ]

    },

    {

      "name":"南沙群岛","id":"900001","child":null    }

  ];

  vareText = document.getElementById('input');

  newCascadeMenu(eText,json);

USB Microphone https://www.soft-voice.com/

Wooden Speakers  https://www.zeshuiplatform.com/

亚马逊测评 www.yisuping.cn

深圳网站建设www.sz886.com

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,548评论 0 11
  • 彩排完,天已黑
    刘凯书法阅读 4,182评论 1 3
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 124,060评论 2 7