当前位置:   article > 正文

element puls的select下拉选择加Tree V2 虚拟化树形控件实现简易下拉选择,替代vue3-treeselect插件的基础功能(代码记录, copy可直接使用)_el-tree-select-v2

el-tree-select-v2

element puls的select下拉选择加Tree V2 虚拟化树形控件实现简易下拉选择

前言
在vue3+typescript项目中,需要使用到下拉树形选择功能,npm vue3-treeselect后使用中有很多问题和不兼容ts。
原本也只需要简单的选择功能,就照着网上现写了一个简易的下拉选择(element puls select + tree v2)

组件的模板
<template>
  <div class="tree_box" :style="width && {width: width.includes('px') ? width : width + 'px'}">
    <el-select v-model="value" clearable filterable ref="treeSelect" :placeholder="placeholder || '请选择'" 
    :filter-method="selectFilter" @clear="clearSelected">
      <el-option :value="currentNodeKey" :label="currentNodeLabel">
        <el-tree-v2
          id="tree_v2"
          ref="treeV2"
         :data="options"
         :props="keyProps || TreeProps"
         :height="240"
         :current-node-key="currentNodeKey"
         @node-click="nodeClick"
         :expand-on-click-node="false"
         :filter-method="treeFilter"
        ></el-tree-v2>
      </el-option>
    </el-select>
  </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
typescript部分
<script lang="ts">
import { TreeNode } from 'element-plus/es/components/tree-v2/src/types'
import { TreeNodeData } from 'element-plus/es/components/tree/src/tree.type'
import { defineComponent, nextTick, onMounted, PropType, reactive, ref, toRefs, watch } from 'vue'
interface PropsIter {
  value:string
  label:string
  children:string
  disabled?:boolean
}
const TreeProps:PropsIter = {
  value: 'id',
  label: 'label',
  children: 'children'
}
interface TreeIter {
  id: string
  label: string
  children?: TreeIter[]
}
export default defineComponent({
  name: 'tree select',
  props: {
  	// 组件绑定的options
    options: {
      type: Array as PropType<TreeIter[]>,
      required: true
    },
    // 配置选项
    keyProps: Object as PropType<PropsIter>,
    // 双向绑定值
    modelValue: [String, Number],
    // 组件样式宽
    width: String,
    // 空占位字符
    placeholder: String
  },
  setup (props, { emit }) {
    // 解决 props道具变异
    const { modelValue } = toRefs(props)
    const select:any = reactive({
      value: modelValue.value,
      currentNodeKey: '',
      currentNodeLabel: ''
    })
    const treeSelect = ref<HTMLElement | null>(null)
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    const nodeClick = (data: TreeNodeData, node: TreeNode) => {
      select.currentNodeKey = data.id
      select.currentNodeLabel = data.label
      select.value = data.id;
      (treeSelect.value as any).blur()
      emit('update:modelValue', select.value)
    }
    // select 筛选方法 treeV2 refs
    const treeV2:any = ref<HTMLElement | null>(null)
    const selectFilter = (query:string) => {
      treeV2.value.filter(query)
    }
    // ztree-v2 筛选方法
    const treeFilter = (query:string, node: TreeNode) => {
      return node.label?.indexOf(query) !== -1
    }
    // 直接清空选择数据
    const clearSelected = () => {
      select.currentNodeKey = ''
      select.currentNodeLabel = ''
      select.value = ''
      emit('update:modelValue', undefined)
    }
    // setCurrent通过select.value 设置下拉选择tree 显示绑定的v-model值
    // 可能存在问题:当动态v-model赋值时 options的数据还没有加载完成就会失效,下拉选择时会警告 placeholder
    const setCurrent = () => {
      select.currentNodeKey = select.value
      treeV2.value.setCurrentKey(select.value)
      const data:TreeNodeData | undefined = treeV2.value.getCurrentNode(select.value)
      select.currentNodeLabel = data?.label
    }
    // 监听外部清空数据源 清空组件数据
    watch(modelValue, (v) => {
      if (v === undefined && select.currentNodeKey !== '') {
        clearSelected()
      }
      // 动态赋值
      if (v) {
        select.value = v
        setCurrent()
      }
    })
    // 回显数据
    onMounted(async () => {
      await nextTick()
      if (select.value) {
        setCurrent()
      }
    })
    return {
      treeSelect,
      treeV2,
      TreeProps,
      ...toRefs(select),
      nodeClick,
      selectFilter,
      treeFilter,
      clearSelected
    }
  }
})
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
组件样式修改
<style lang="less" scoped>
.tree_box{
  width: 214px;
}
.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 :deep(.el-tree .el-tree-node__content) {
  height: auto;
  padding: 0 20px;
}

.el-tree-node__label {
  font-weight: normal;
}

.el-tree :deep(.is-current .el-tree-node__label) {
  color: #409eff;
  font-weight: 700;
}

.el-tree :deep(.is-current .el-tree-node__children .el-tree-node__label) {
  color: #606266;
  font-weight: normal;
}
.selectInput {
  padding: 0 5px;
  box-sizing: border-box;
}
.el-select{
  width: 100% !important;
}
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
使用组件
<com-tree-select :options="unitTreeOptions" v-model="searchForm.unitId" placeholder="单位名称" />
  • 1
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号