使用面向对象的方式封装js级联下拉菜单列表的实例教程

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

打开后的级联菜单效果如图所示:
在这里插入图片描述

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

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

样式可以根据图片上的效果自己编写,也可以从 《使用面向对象的方式封装js级联下拉菜单列表的实例教程》源码 中复制。

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

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

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

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

  }
  1. 在构造函数中创建级联菜单相关元素,并放到页面中,具体代码如下:
  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;
  }
  1. 在文本框上绑定点击事件,生成级联下拉菜单

刚才已经把需要的元素都放到了页面中,现在可以通过点击文本框显示和隐藏级联菜单元素;
在显示级联菜单元素时,应该要通过数据生成级联下拉菜单。
因为每次点击都需要生成,所以可以在构造函数的原型上添加一个方法。如下所示:

  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 class="child cur" data-po="'+step+'">';
          }else{
   
            sHTML += '<li class="child" data-po="'+step+'">';
          }
        }else{
     
          //如果没有子菜单,直接加到菜单列表中
          sHTML += data[i].name == this.aSelected[step]?
                                   '<li class="cur" 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);
  }
  1. 菜单上绑定事件,用于选择菜单

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

  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();
      }    
    });
  }
  1. 在页面空白处点击时,隐藏菜单

现在只能在文本框上点击显示和隐藏菜单。一般来说任何打开的弹框,都希望在弹框以外的位置可以关闭掉。这样需要修改一下文本框上的点击事件函数:当打开菜单时,要在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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值