<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>线性数据 转树状选择框demo</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      /* 共享部分开始 */
      ul.parent {
        border: 1px solid #f1f1f1;
        min-width: 200px;
        position: absolute;
        background: #fff;
        display: none;
      }
      ul.child {
        border: 1px solid #f1f1f1;
        background: #fff;
        min-width: 200px;
      }
      ul.parent li {
        list-style: none;
        height: 30px;
        line-height: 30px;
        position: relative;
        text-indent: 10px;
        font-size: 14px;
        cursor: pointer;
        color: #000;
      }
      ul.parent li:hover {
        background: #4471d6;
        color: #fff;
      }
      ul.parent li > .child {
        border: 1px solid #ccc;
        background: #fff;
        display: none;
        position: absolute;
      }
      ul.parent li > .font_right {
        float: right;
        margin-right: 8px;
      }
      /* 共享部分结束 */

      .mybox {
        width: 300px;
        margin: 0 auto;
      }
      .mySpan,
      .myDiv {
        display: inline-block;
        width: 200px;
        height: 40px;
        border: 1px solid;
      }
    </style>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
  </head>
  <body>
    <div class="mybox">
      <div>
        <input type="text" class="myInput" />
      </div>
      <div>
        <span class="mySpan"></span>
      </div>
      <div>
        <div class="myDiv"></div>
      </div>
    </div>
    <script type="text/javascript">
      /**
       * data 渲染数据
       * options doms: 回显处doms  isChooseEnd: 是否选择到最末级 true必须选最末级
       */
      class MyTree {
        constructor(data, options, callBack) {
          this.data = data
          this.options = options
          this.menus = '' //菜单列表html
          this.callBack = callBack
        }
        init() {
          this.renderHtml()
          this.bindEvent()
        }
        renderHtml() {
          this.GetData('', this.data)
          this.options.doms.forEach((v, i) => {
            v.after(this.menus)
          })
        }
        /**
         *   根据菜单主键id生成菜单列表html
         *   id:菜单主键id
         *   arry:菜单数组信息
         */
        GetData(id, arry) {
          var childArry = this.GetParentArry(id, arry)
          if (childArry.length > 0) {
            if (!!this.menus) {
              this.menus += '<ul class="child">'
            } else {
              this.menus += '<ul class="parent">'
            }
            for (var i in childArry) {
              var children = this.GetParentArry(childArry[i].id, arry) // 子集数组
              this.menus +=
                `<li data-id='${childArry[i].id}' data-name='${
                  childArry[i].name
                }' data-isChild=${children.length > 0 ? true : false}>` +
                childArry[i].name
              this.menus +=
                children.length > 0 ? `<span class="font_right"> > </span>` : ''
              this.GetData(childArry[i].id, arry)
              this.menus += '</li>'
            }
            this.menus += '</ul>'
          }
        }
        /**
         *   根据菜单主键id获取下级菜单
         *   id:菜单主键id
         *   arry:菜单数组信息
         */
        GetParentArry(id, arry) {
          var newArry = new Array()
          for (var i in arry) {
            if (arry[i].pid == id) newArry.push(arry[i])
          }
          return newArry
        }
        bindEvent() {
          var self = this
          // 鼠标移入时增加标识show并且其它子元素的child隐藏 自己的显示
          $('ul.parent li').on('mouseenter', function(e) {
            $(this)
              .addClass('show')
              .siblings()
              .children('.child')
              .hide()
            $(this)
              .children()
              .css({ left: $(this).width(), top: '-1px' })
              .show()
          })

          // 同级别li相互切换时只能保留一个选中状态
          $('ul.parent li').on('mouseleave', function() {
            $(this).removeClass('show')
          })

          // 移出主数据框消失
          $('ul.parent').on('mouseleave', function() {
            $(this)
              .parent()
              .css('position', 'inherit')
            $('.child').hide()
            $('.parent').hide()
          })

          // 移出子集框该子集消失
          $('ul.child').on('mouseleave', function() {
            $(this)
              .parent('.parent')
              .parent()
              .css('position', 'inherit')
            $(this)
              .hide()
              .children()
              .removeClass('show')
          })

          // 选择时得到结果
          $('ul.parent li').on('click', function(e) {
            var nameArr = []
            var idArr = []
            if (self.options.isChooseEnd) {
              if ($(this).data('ischild')) {
                return false
              }
            }
            $('.show').each((i, v) => {
              nameArr.push($(v).data('name'))
              idArr.push($(v).data('id'))
            })
            // 将数据回显到传值处
            if (
              $(this)
                .closest('.parent')
                .siblings()[0].tagName == 'INPUT'
            ) {
              $(this)
                .closest('.parent')
                .siblings()
                .val(nameArr.join('>'))
                .attr('title', nameArr.join('>'))
            } else {
              $(this)
                .closest('.parent')
                .siblings()
                .text(nameArr.join('>'))
                .attr('title', nameArr.join('>'))
            }
            $(this)
              .closest('.parent')
              .parent()
              .css({ position: 'inherit' })
            $('.child').removeClass('show')
            $('.parent').hide()
            // 如果有回调函数
            if (self.callBack) {
              self.callBack({
                nameArr: nameArr,
                idArr: idArr,
                dom: $(this)
                  .closest('.parent')
                  .siblings()
              })
            }
            e.stopPropagation()
            e.preventDefault()
          })

          // 传入的dom点击事件
          self.options.doms.forEach((v, i) => {
            v.on('click', function(e) {
              $(this)
                .siblings('.parent')
                .show()
                .parent()
                .css({ position: 'relative' })
            })
          })
        }
      }

      $(function() {
        var data = [
          { id: '001', name: '办公管理办公管理办公管理办公管理', pid: '' },
          { id: '002', name: '请假申请', pid: '001' },
          { id: '003', name: '出差申请', pid: '001' },
          { id: '004', name: '请假记录', pid: '002' },
          { id: '005', name: '系统设置', pid: '' },
          { id: '006', name: '权限管理', pid: '005' },
          { id: '007', name: '用户角色', pid: '006' },
          { id: '008', name: '菜单设置', pid: '006' },
          { id: '009', name: '测试数据1', pid: '007' },
          { id: '010', name: '测试数据2', pid: '007' }
        ]

        var mytree = new MyTree(
          data,
          {
            doms: [$('.myInput'), $('.mySpan'), $('.myDiv')],
            isChooseEnd: true // 是否只能选择到最末级
          },
          function(res) {
            console.log('回调值:', res)
          }
        )
        mytree.init()
      })
    </script>
  </body>
</html>

效果图如下

效果图

posted on 2020-03-07 13:33  佑之以航  阅读(158)  评论(0编辑  收藏  举报