vue2-级联选择器

一、市面上的级联选择器

用多了组件库以后,发现各种级联选择器都有很多问题,用着很不方便

1、比如我有三级,我只能点击我最后一个级别的时候,我的下拉框才会收回,
2、很多组件都没法实现光点击我的一级或者二级菜单,必须要点击最后一级菜单
3、 而且传的值也是一个数组类型的,处理起来要判断,很麻烦,没法我点击一个传递一个ID

所以我根据功能自己写了一个三级下拉框,

二、功能实现

1、数据类型

数据类型为树形结构,我贴上我的数据

dataList: {
        name: '总经理',
        code: 1,
        level: 1,
        isSaleDepartment: false,
        nodes: [
          {
            name: '管理部',
            code: 11,
            level: 2,
            isSaleDepartment: false,
            nodes: [
              {
                name: '人事',
                code: 111,
                level: 3,
                isSaleDepartment: true,
                nodes: [],
                id: 8,
              },
              {
                name: '行政',
                code: 112,
                level: 3,
                isSaleDepartment: true,
                nodes: [],
                id: 9,
              },
              {
                name: '采购',
                code: 113,
                level: 3,
                isSaleDepartment: true,
                nodes: [],
                id: 10,
              },
              {
                name: '仓库',
                code: 114,
                level: 3,
                isSaleDepartment: true,
                nodes: [],
                id: 11,
              },
              {
                name: '财务',
                code: 115,
                level: 3,
                isSaleDepartment: true,
                nodes: [],
                id: 12,
              },
            ],
            id: 2,
          },
          {
            name: '销售部',
            code: 12,
            level: 2,
            isSaleDepartment: true,
            nodes: [
              {
                name: '销售部门1',
                code: 121,
                level: 3,
                isSaleDepartment: true,
                nodes: [],
                id: 13,
              },
              {
                name: '销售部门2',
                code: 122,
                level: 3,
                isSaleDepartment: true,
                nodes: [],
                id: 14,
              },
              {
                name: '销售部门3',
                code: 123,
                level: 3,
                isSaleDepartment: true,
                nodes: [],
                id: 15,
              },
              {
                name: '销售部门4',
                code: 124,
                level: 3,
                isSaleDepartment: true,
                nodes: [],
                id: 16,
              },
            ],
            id: 3,
          },
          {
            name: '业务部',
            code: 13,
            level: 2,
            isSaleDepartment: false,
            nodes: [
              {
                name: '销售',
                code: 131,
                level: 3,
                isSaleDepartment: false,
                nodes: [],
                id: 17,
              },
              {
                name: '市场开发',
                code: 132,
                level: 3,
                isSaleDepartment: false,
                nodes: [],
                id: 18,
              },
              {
                name: '售后服务',
                code: 133,
                level: 3,
                isSaleDepartment: false,
                nodes: [],
                id: 19,
              },

            ],
            id: 4,
          },
          {
            name: '工程部',
            code: 14,
            level: 2,
            isSaleDepartment: false,
            nodes: [
              {
                name: '新产品开发',
                code: 141,
                level: 3,
                isSaleDepartment: false,
                nodes: [],
                id: 20,
              },
              {
                name: '产品设计',
                code: 142,
                level: 3,
                isSaleDepartment: false,
                nodes: [],
                id: 21,
              },
              {
                name: '产品工艺',
                code: 143,
                level: 3,
                isSaleDepartment: false,
                nodes: [],
                id: 22,
              },
              {
                name: '资料管理',
                code: 144,
                level: 3,
                isSaleDepartment: false,
                nodes: [],
                id: 23,
              },


            ],
            id: 5,
          },
          {
            name: '生产部',
            code: 15,
            level: 2,
            isSaleDepartment: false,
            nodes: [
              {
                name: '生产计划',
                code: 151,
                level: 3,
                isSaleDepartment: false,
                nodes: [],
                id: 24,
              },
              {
                name: '设备制造',
                code: 152,
                level: 3,
                isSaleDepartment: false,
                nodes: [],
                id: 25,
              },
              {
                name: '工程安装',
                code: 153,
                level: 3,
                isSaleDepartment: false,
                nodes: [],
                id: 26,
              },

            ],
            id: 6,
          },
          {
            name: '品质部',
            code: 16,
            level: 2,
            isSaleDepartment: false,
            nodes: [
              {
                name: '质量管理',
                code: 161,
                level: 3,
                isSaleDepartment: false,
                nodes: [],
                id: 27,
              },
              {
                name: '过程控制',
                code: 162,
                level: 3,
                isSaleDepartment: false,
                nodes: [],
                id: 28,
              },
            ],
            id: 7,
          },
        ],
        id: 1,
      },

2、隐藏下拉框的方法

 hideDropdown() {
      this.showDropdown = false;
      this.currentProvinceName = null;
      this.currentCityName = null;
    },

3、html结构

我是用原生的div和ul以及li标签实现的

 <div class="app">
    <div class="dropdown" @mouseleave="hideDropdown">
      <div
        @click="showDropdown = !showDropdown"
        @mouseenter="showclose = true"
        @mouseleave="showclose = false"
        :style="{ width: widthLength }"
        class="selectContent"
        :class="showDropdown ? 'active' : ''"
      >
        <span style="color: #ccc" v-if="selectedText === '请选择'">{{
          selectedText
        }}</span>
        <span v-else>{{ selectedText }}</span>

        <Icon
          class="icon"
          type="md-close"
          v-if="
            selectedText &&
            selectedText !== '请选择' &&
            showclose &&
            showcloseIcon
          "
          @click.stop="clear"
        />
      </div>

      <ul class="menu" v-if="showDropdown">
        <li
          @click.stop="clickFirst(dataList)"
          @mouseenter="showSubmenu(dataList)"
        >
          {{ dataList.name }}
          <!-- <div class="arrow-down" v-if="dataList.nodes.length > 0"></div> -->
          <!-- <Icon v-if="dataList.nodes.length > 0" type="ios-arrow-forward" /> -->
          <ul
            v-if="
              currentProvinceName === dataList.name && dataList.nodes.length > 0
            "
            class="submenu"
          >
            <li
              class="secondMenu"
              v-for="second in dataList.nodes"
              :key="second.id"
              @click.stop="clickSecond(dataList.name, second)"
              @mouseenter="showSubmenuSecond(second)"
            >
              {{ second.name }}
              <Icon v-if="second.nodes.length > 0" type="ios-arrow-forward" />
              <ul
                v-if="
                  currentCityName === second.name && second.nodes.length > 0
                "
                class="thiredMe"
              >
                <li
                  class="thirdMenu"
                  v-for="third in second.nodes"
                  :key="third.id"
                  @click.stop="selectDistrict(dataList.name, second, third)"
                >
                  {{ third.name }}
                </li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </div>
  </div>

4、CSS代码

<style scoped>
   .arrow-down {
            width: 0;
            height: 0;
            border-left: 10px solid transparent;
            border-right: 10px solid transparent;
            border-top: 10px solid black;
        }
.app {

  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  margin: 0 auto;
}
.active {
  border-color: #57a3f3;
  outline: 0;
  box-shadow: 0 0 0 2px rgba(45, 140, 240, 0.2);
}
.icon {
  position: absolute;
  right: 5px;
  font-size: 16px;
}
.selectContent {
  border: 1px solid #ccc;
  border-radius: 3px;
  position: relative;

  height: 32px;
  padding: 0 24px 0 8px;
  display: flex;
  align-items: center;
}
.selectContent:hover {
  border-color: #57a3f3;
  outline: 0;
  box-shadow: 0 0 0 2px rgba(45, 140, 240, 0.2);
}
.dropdown {
  display: inline-block;
  position: relative;
  cursor: pointer;
  z-index: 1000;
}
.dropdown .menu {
  list-style-type: none;
  padding: 0;
  margin: 0;
  position: absolute;
  top: 102%;
  left: 0;
  background: white;
  border: 1px solid #ccc;
  border-radius: 5px;
  z-index: 1000;
  width: 100px;
}
.dropdown .menu > li {
  padding: 8px;
  cursor: pointer;
  position: relative;
}
.dropdown .menu > li:hover {
  background: #f3f3f3;
}
.secondMenu {
  padding: 5px;
  position: relative;
}
.secondMenu:hover {
  background: #f3f3f3;
}
.dropdown .submenu {
  list-style-type: none;
  padding: 0;
  margin: 0;
  position: absolute;
  top: 0;
  left: 100%;
  background: white;
  border: 1px solid #ccc;
  border-radius: 5px;
  display: none;
  z-index: 500;
  width: 100px;
  /* max-height: 200px;
  overflow-y: auto; */
  max-height: 200px; /* 设置固定高度 */
}
.thiredMe {
  border: 1px solid #ccc;

  position: absolute;
  left: 100%;
  width: 100px;
  top: 0;
  z-index: 1001;
  background: white;
  border-radius: 5px;
  list-style-type: none;
  height: 150px;
  overflow: auto;
}
.thirdMenu {
  padding: 5px;
  position: relative;

}
.thirdMenu:hover {
  background: #f3f3f3;
}
.dropdown .menu > li:hover > .submenu {
  display: block;
}
ul {
  padding-left: 0 !important;
 }
</style>

5、各个方法代码

methods: {
    showSubmenu(item) {
      this.currentProvinceName = item.name;
      this.currentCityName = null;
    },
    showSubmenuSecond(item) {
      this.currentCityName = item.name;
    },
    hideDropdown() {
      this.showDropdown = false;
      this.currentProvinceName = null;
      this.currentCityName = null;
    },
    // 点击一级菜单
    clickFirst(first) {
      this.$emit('current', first);
      this.selectedText = first.name;
      this.hideDropdown();
    },
    // 点击二级菜单
    clickSecond(firstname, second) {
      this.$emit('current', second);
      this.selectedText = firstname + '-' + second.name;
      this.hideDropdown();
    },
    // 点击三级菜单
    selectDistrict(first, second, third) {
      console.log('firs', first, second.name, third.name);
      this.selectedText = first + '-' + second.name + '-' + third.name;
      this.hideDropdown();
      this.$emit('current', third);
    },
  },

三、实现样式截图

1、一级菜单

1、鼠标放到一级菜单,就显示二级菜单

在这里插入图片描述

2、鼠标点击一级菜单的时候

就直接显示一级的内容,并且下拉框也是隐藏状态
在这里插入图片描述

2、二级菜单

1、鼠标放到二级菜单的时候,显示三级菜单

在这里插入图片描述

2、鼠标点击二级菜单的时候,显示一级菜单和二级菜单

并且下拉框也是隐藏状态
在这里插入图片描述

3、三级菜单

1、鼠标点击三级菜单的时候

直接显示三个菜单的内容,并且下拉框隐藏了,
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值