一、先看效果

在这里插入图片描述

二、组件具体实现

借鉴了网上前端大佬的实现,加上自己在使用过程中发现的一些BUG,做了一些改进。主要可以支持动态表单的特性及v-model,支持禁用,支持放在表单中使用,下面请看代码。

主要借鉴文章:https://wiill.blog.csdn.net/article/details/88604270

  1. 组件模板
<template>
  <el-select :value="valueTitle" :disabled="disabled" :clearable="clearable" @clear="clearHandle">
    <el-option :value="valueTitle" :label="valueTitle">
      <el-tree  id="tree-option"
                ref="selectTree"
                :accordion="accordion"
                :data="options"
                :props="props"
                :node-key="props.value"
                :default-expanded-keys="defaultExpandedKey"
                @node-click="handleNodeClick">
      </el-tree>
    </el-option>
  </el-select>
</template>
  1. 配套script
<script>
  export default {
    name: 'ebs-tree-select',
    props:{
      /* 配置项 */
      props:{
        type: Object,
        default:()=>{
          return {
            value:'id',             // ID字段名
            label: 'title',         // 显示名称
            children: 'children'    // 子级字段名
          }
        }
      },
      /* 选项列表数据(树形结构的对象数组) */
      options:{
        type: Array,
        default: ()=>{ return [] }
      },
      /* 初始值 */
      value:{
        type: String,
        default: ()=>{ return null }
      },
      /* 可清空选项 */
      clearable:{
        type:Boolean,
        default:()=>{ return true }
      },
      /* 自动收起 */
      accordion:{
        type:Boolean,
        default:()=>{ return false }
      },
      disabled: {
        type:Boolean,
        default:()=>{ return false }
      }
    },
    data() {
      return {
        valueId:this.value,    // 初始值
        valueTitle:'',
        defaultExpandedKey:[]
      }
    },
    mounted(){
      this.initHandle()
    },
    methods: {
      // 初始化值
      initHandle(){
        // alert('this.valueId=' + this.valueId)
        let that = this
        // 这里要延迟执行,否则有BUG
        setTimeout(function() {
          if(that.valueId){
            that.valueTitle = that.$refs.selectTree.getNode(that.valueId).data[that.props.label]     // 初始化显示
            that.$refs.selectTree.setCurrentKey(that.valueId)       // 设置默认选中
            that.defaultExpandedKey = [that.valueId]      // 设置默认展开
          } else {
            that.valueTitle = null // 初始化显示
            that.$refs.selectTree.setCurrentKey(null) // 设置默认选中
          }
        },200)
        this.$nextTick(()=>{
          let scrollWrap = document.querySelectorAll('.el-scrollbar .el-select-dropdown__wrap')[0]
          let 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.$emit('input',this.valueId)
        this.defaultExpandedKey = []
      },
      // 清除选中
      clearHandle(){
        this.valueTitle = ''
        this.valueId = null
        this.defaultExpandedKey = []
        this.clearSelected()
        //this.$emit('getValue',null)
        this.$emit('input',null)
      },
      /* 清空选中样式 */
      clearSelected(){
        let 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>
  1. 样式
<style scoped>
  .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;
  }
  .el-tree-node__label{
    font-weight: normal;
  }
  .el-tree >>>.is-current .el-tree-node__label{
    color: #409EFF;
    font-weight: 700;
  }
  .el-tree >>>.is-current .el-tree-node__children .el-tree-node__label{
    color:#606266;
    font-weight: normal;
  }
</style>

具体使用

<ebs-tree-select v-else-if="field.view=='cat_tree'" 
	:props="treeSelectProps" 
	v-model="form[field.fieldName]"
	:options="catTreeData[field.fieldName]" 
	v-bind:disabled="isView">
</ebs-tree-select>
补充说明:
  1. 使用 treeSelectProps 解决数据字段名不匹配问题
  treeSelectProps: {
    value: 'key',             // ID字段名
    label: 'title',         // 显示名称
    children: 'children'    // 子级字段名
  }
  1. 因为我这里是动态表单字段,所以是 form[field.fieldName],你可以直接写form.xxxx
  2. 因为是动态表单,考虑一个表单有多个选树字段,故这里写catTreeData[field.fieldName],非我这类场景,你可以直接写catTreeData,里面就说数组对象,多层级即可,可参考如下JSON:
[
  {
    "key": "1462626865326317569",
    "title": "基础管理",
    "icon": null,
    "parentId": "1462626811047829505",
    "value": null,
    "code": "B03A01",
    "children": null,
    "leaf": true
  },
  {
    "key": "1462626933466980354",
    "title": "在线开发",
    "icon": null,
    "parentId": "1462626811047829505",
    "value": null,
    "code": "B03A02",
    "children": [
      {
        "key": "1462627031668219905",
        "title": "表单开发",
        "icon": null,
        "parentId": "1462626933466980354",
        "value": null,
        "code": "B03A02A01",
        "children": null,
        "leaf": true
      },
      {
        "key": "1462627069307904002",
        "title": "报表配置",
        "icon": null,
        "parentId": "1462626933466980354",
        "value": null,
        "code": "B03A02A02",
        "children": null,
        "leaf": true
      }
    ],
    "leaf": false
  }
]
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐