您的位置:首页技术文章
文章详情页

js面向对象封装级联下拉菜单列表的实现步骤

【字号: 日期:2024-04-05 17:44:40浏览:34作者:猪猪

本实例开发的级联下拉菜单是根据已有json数据创建的DOM元素。点击文本框后,显示一级菜单。如果菜单中包含子菜单,菜单右侧会有指示箭头。点击菜单之后,会再显示下一级菜单,以此类推。当菜单下无子菜单时,选择菜单后会在文本框中显示。

打开后的级联菜单效果如图所示:

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 = ’请选择’; //获取文本框父元素 var eInputParent = 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调用实例对象需要声明一个变量指向this var _self = this; //因为不确定子菜单有多少组,所以需要声明一个函数来递归调用 //data:传入数据,step:当前级别 function fnCreatHTML(data,step){ //用于存储子菜单数据 var aChildArr = null; //生成菜单DOM的字符串 var sHTML = ’<ul>’; //循环数据 for(let i=0;i<data.length;i++){ //判断如果有子菜单,添加child的class,用于显示菜单右侧箭头 if(data[i].child){ //判断是否是当前选择,如果是,加上cur class,并且存储子菜单数据 if(data[i].name==this.aSelected[step]){ aChildArr = data[i].child; sHTML += ’<li data-po='’+step+’'>’; }else{ sHTML += ’<li data-po='’+step+’'>’; } }else{ //如果没有子菜单,直接加到菜单列表中 sHTML += data[i].name == this.aSelected[step]? ’<li data-po='’+step+’'>’: ’<li data-po='’+step+’'>’; } //添加菜单名称 sHTML += data[i].name; //结束当前菜单 sHTML += ’</li>’; } sHTML += ’</ul>’; //如果已选择多个菜单,递归调用函数,生成子菜单 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)=>{ //获取菜单 var eTarget = event.target; //获取选择的级别 var po = +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. 最后,准备好数据,调用构造函数,生成级联下拉菜单,如下所示:

var json = [ { '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 } ]; var eText = document.getElementById(’input’); new CascadeMenu(eText,json);

一个封装好的js级联下拉功能就完成了,可以根据图片自己编写css样式以达到需要的效果。

以上就是js面向对象封装级联下拉菜单列表的实现步骤的详细内容,更多关于js 封装下拉菜单的资料请关注好吧啦网其它相关文章!

标签: JavaScript
相关文章: