elementUI实现selecttree自定义下拉框树形组件

elementUI有select组件也有tree组件,但是就是没有下拉框和tree组件的结合体,那么这次我们就自定义一个。


效果图

elementUI实现selecttree自定义下拉框树形组件_第1张图片

引入组件
<select-tree ref="selectTree" @treeChange="treeChangeFun" :dataArray="orgList" :value="currentValue" />

import selectTree from '@/components/selectTree.vue'
components: {
    selectTree
},
treeChangeFun (val) {
   console.log(val)
},

注意点:

  • treeChange为子组件的emit函数
  • dataArray为tree的数据,形式为父子嵌套结构
  • value为默认选中的节点id(也可能是其他key,以node-key定义的值为准),如果没有默认选中节点的需求,也可以不考虑此参数
编写组件js

源码如下:

<template>
    <div class="selectTree">
        <el-select class="main-select-tree" ref="selectTree" v-model="transitValue">
            <el-option v-for="item in selectOptions" :key="item.id" :label="item.name" :value="item.id" style="display: none;" />
            <el-tree class="main-select-el-tree" ref="selecteltree" :highlight-current="true" :data="dataArray" :props="defaultProps" :expand-on-click-node="false" node-key="id" @node-click="handleNodeClick" :current-node-key="currentKey" :default-expanded-keys="[value]" />
        </el-select>
    </div>
</template>
<script>
export default {
  name: 'selectTree',
  props: {
    dataArray: Array,
    value: [Number, String]
  },
  data () {
    return {
      transitValue: '',
      selectOptions: [],
      currentKey: null,
      defaultProps: {
        label: 'name',
        children: 'children'
      }
    }
  },
  computed: {
    formatData () {
      let result = []
      function getChild (item) {
        item.forEach((i, x) => {
          if (Array.isArray(i['children'])) {
            result.push(i)
            getChild(i['children'])
          } else {
            result.push(i)
          }
        })
      }
      getChild(this.dataArray)
      return result
    }
  },
  methods: {
    handleNodeClick (node) {
      this.$emit('treeChange', node)
      this.transitValue = node.id
      this.$refs.selectTree.blur()
    }
  },
  watch: {
    formatData (n) {
      if (n.length > 0) {
        this.selectOptions = n
      } else {
        this.selectOptions = []
      }
    },
    value: {
    //   immediate: true,
    //   deep: true,
      handler: function (n) {
        if (n.toString()) {
          this.$nextTick(() => {
            this.transitValue = n
            this.currentKey = this.value
            this.$refs['selecteltree'].setCurrentKey(this.currentKey)
          })
        } else {
          this.$nextTick(() => {
            this.transitValue = n
            this.currentKey = this.value
            this.$refs['selecteltree'].setCurrentKey(null)
          })
        }
      }
    }
  }
}
</script>
<style lang="less" scoped>
/deep/ .el-tree-node.is-current>.el-tree-node__content {
    color: #409EFF;
}
</style>

注意点:

  • 可以看到我们在select里面正常的包裹了option,这是为了依靠option来撑起下拉区域高度,设置样式为display:none
  • 同时和option平级的地方包裹了tree组件,这是实际要展示的效果组件。
  • transitValue是select组件的model值,selectOptions是option的值数组,currentKey是初始化时默认选中节点,defaultProps是tree数据的映射对象。
  • formatData函数的功能是将嵌套数组转化成平铺为一级的一维数组,方便option组件遍历展示。
  • handleNodeClick是tree的单击事件,这里触发子组件的emit事件。
  • watch里的formatData用于检测数据变化动态渲染option。
  • watch里的value用于实时检测value值,用来确定子组件tree的选中项(此操作用于初始化组件时,或者父组件重置条件,或者其他不通过直接点击子组件tree节点改变选中项值的操作)。

你可能感兴趣的:(前端,elementui,javascript,vue.js)