vue2 el-select 改造成下拉树,支持数据回显

简介: 下拉树 就是一个下拉框里面的options里面换成一棵树的形状。本人业务需要一个这样的组件,我也懒得去发布一个组件到npm库,毕竟现在vue3出来了,这个组件只适合vue2 并且是element ui的基础,限制条件有点多。所以在这里做个笔记,有需要的自己copy 代码到自己本地,就行。

下拉树 就是一个下拉框里面的options里面换成一棵树的形状。本人业务需要一个这样的组件,我也懒得去发布一个组件到npm库,毕竟现在vue3出来了,这个组件只适合vue2 并且是element ui的基础,限制条件有点多。所以在这里做个笔记,有需要的自己copy 代码到自己本地,就行。


效果


20210408131002584.gif


下面的底色不要在意哈


使用方式


模板文件


 <select-tree
           :value="test"
           :options="options"
           :props="{
            value: 'id', // ID字段名
            label: 'label', // 显示名称
            children: 'children' // 子级字段名
            }"
           :filterable="true"
         />


数据


看到这个数据,肯定明白,组件已经支持了数据回显。


 test: '1-1',
      // 测试树数据
  options: [
        {
          label: '一级 1',
          id: '1',
          children: [{
            label: '二级 1-1',
            id: '1-1',
            children: [{
              id: '1-1-1',
              label: '三级 1-1-1'
            }]
          }]
        }, {
          label: '一级 2',
          id: '2',
          children: [{
            label: '二级 2-1',
            id: '2-1',
            children: [{
              id: '2-1-1',
              label: '三级 2-1-1'
            }]
          }, {
            id: '2-2',
            label: '二级 2-2',
            children: [{
              id: '2-2-1',
              label: '三级 2-2-1'
            }]
          }]
        }]


组件代码


组件名称 SelectTree.vue, 如果需要加上disabled 或者个性化的, 自己可以手动添加,代码已经有注释了


<template>
  <div class="tree_select">
    <el-select :value="valueTitle"
               ref="selectEl"
               :filterable="filterable"
               :clearable="clearable"
               @clear="clearHandle"
               :filter-method="selectFilterData"
               :size="size">
      <el-option :value="valueId" :label="valueTitle">
        <el-tree id="tree-option"
                 ref="selectTree"
                 :accordion="accordion"
                 :data="options"
                 :props="props"
                 :node-key="props.value"
                 :expand-on-click-node="false"
                 :default-expanded-keys="defaultExpandedKey"
                 :filter-node-method="filterNode"
                 @node-click="handleNodeClick">
        </el-tree>
      </el-option>
    </el-select>
  </div>
</template>
<script>
export default {
  name: 'SelectTree',
  props: {
    /* 配置项 */
    props: {
      type: Object,
      default: () => {
        return {
          value: 'id', // ID字段名
          label: 'title', // 显示名称
          children: 'children' // 子级字段名
        }
      }
    },
    /* 选项列表数据(树形结构的对象数组) */
    options: {
      type: Array,
      default: () => {
        return []
      }
    },
    /* 初始值 */
    value: {
      type: [Number, String],
      default: () => {
        return null
      }
    },
    /* 可清空选项 */
    clearable: {
      type: Boolean,
      default: () => {
        return true
      }
    },
    /* 自动收起 */
    accordion: {
      type: Boolean,
      default: () => {
        return false
      }
    },
    /**
     * 下拉选项框的大小,默认最小
     */
    size: {
      type: String,
      default: () => {
        return 'mini'
      }
    },
    // 是否可以搜索
    filterable: Boolean
  },
  data () {
    return {
      valueId: this.value, // 初始值
      valueTitle: '',
      defaultExpandedKey: []
    }
  },
  mounted () {
    this.$nextTick(function () {
      this.initHandle()
    })
  },
  methods: {
    // 初始化值
    initHandle () {
      if (this.valueId) {
        this.valueTitle = this.$refs.selectTree.getNode(this.valueId).data[this.props.label] // 初始化显示
        this.$refs.selectTree.setCurrentKey(this.valueId) // 设置默认选中
        this.defaultExpandedKey = [this.valueId] // 设置默认展开
      }
      this.$nextTick(() => {
        const scrollWrap = document.querySelectorAll('.el-scrollbar .el-select-dropdown__wrap')[0]
        const scrollBar = document.querySelectorAll('.el-scrollbar .el-scrollbar__bar')
        scrollWrap.style.cssText = 'margin: 0px; max-height: none; overflow: hidden;'
        scrollBar.forEach(ele => {
          ele.style.width = 0
        })
      })
    },
    // 切换选项
    handleNodeClick (node) {
      this.valueTitle = node[this.props.label]
      this.valueId = node[this.props.value]
      this.$emit('getValue', this.valueId)
      this.defaultExpandedKey = []
      // 选中后失去焦点,隐藏下拉框
      this.$refs.selectEl.blur()
      // 把数据还原
      this.selectFilterData('')
    },
    /**
     * 下拉框搜索
     */
    selectFilterData (val) {
      this.$refs.selectTree.filter(val)
    },
    /**
     * 过滤节点
     */
    filterNode (value, data) {
      if (!value) return true
      return data.label.indexOf(value) !== -1
    },
    // 清除选中
    clearHandle () {
      this.valueTitle = ''
      this.valueId = null
      this.defaultExpandedKey = []
      this.clearSelected()
      this.$emit('getValue', null)
    },
    /* 清空选中样式 */
    clearSelected () {
      const allNode = document.querySelectorAll('#tree-option .el-tree-node')
      allNode.forEach((element) => element.classList.remove('is-current'))
    }
  },
  watch: {
    /**
     * 监听绑定的值变化
     */
    value () {
      this.valueId = this.value
      this.initHandle()
    }
  }
}
</script>
<style lang="scss" scoped>
::v-deep .el-select .el-input .el-input__inner {
  color: #fff !important;
}
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
  height: auto;
  max-height: 274px;
  padding: 0;
  overflow: hidden;
  overflow-y: auto;
}
.el-select-dropdown__item.selected {
  font-weight: normal;
}
ul li > > > .el-tree .el-tree-node__content {
  height: auto;
  padding: 0 20px;
}
::v-deep .el-tree-node__content:hover,
::v-deep .el-tree-node__content:active,
::v-deep .is-current > div:first-child,
::v-deep .el-tree-node__content:focus {
  background-color: #F5F7FA;
  color: #409EFF;
}
</style>


相关文章
|
21天前
|
JavaScript 前端开发 开发者
响应式原理:Vue 如何跟踪数据变化
【4月更文挑战第22天】Vue 的响应式系统是其核心,通过数据双向绑定实现视图与数据同步。依赖收集和观测数据使Vue能跟踪变化,变化通知组件更新视图。高效的更新策略如批量更新和虚拟DOM提升性能。组件化和可组合性支持有效通信和代码复用,强调数据驱动开发。开发者应合理组织数据、谨慎处理变更并充分利用组件化优势,以提高效率和用户体验。
|
1月前
Vue3响应式数据ref
Vue3响应式数据ref
|
1月前
|
JavaScript
Vue响应式数据的判断
Vue响应式数据的判断
|
1月前
Vue3 子传父 暴露数据 defineExpose
Vue3 子传父 暴露数据 defineExpose
Vue3 子传父 暴露数据 defineExpose
|
4天前
|
JavaScript
vue3表格编辑(数据回显)和删除功能实现
vue3表格编辑(数据回显)和删除功能实现
9 1
|
4天前
|
JavaScript
vue3使用element-plus 树组件(el-tree)数据回显
vue3使用element-plus 树组件(el-tree)数据回显
7 0
|
7天前
|
JavaScript 索引
vue 在什么情况下在数据发生改变的时候不会触发视图更新
vue 在什么情况下在数据发生改变的时候不会触发视图更新
17 2
|
17天前
|
监控 JavaScript
Vue中的数据变化监控与响应——深入理解Watchers
Vue中的数据变化监控与响应——深入理解Watchers
|
19天前
|
存储 JavaScript 前端开发
父子组件通信:有效地在Vue组件树中传递数据
【4月更文挑战第24天】Vue.js中的组件通信是实现可维护和可扩展代码的关键。遵循单向数据流原则,数据从父组件通过`props`传给子组件,子组件通过`$emit`触发事件响应。常用通信方式包括:1) `Props`和`Events`基础通信;2) `Provide / Inject`跨级通信;3) 使用Vuex管理复杂状态;4) 共享祖先组件或Vuex处理非父子组件通信;5) 少量使用`ref`和`$parent / $children`直接访问。选择合适的方式能优化应用性能和用户体验。
|
21天前
|
JavaScript 前端开发 CDN
Vue数据过滤与this指向的问题
Vue数据过滤与this指向的问题
16 1