index.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <template>
  2. <div class="el-tree-select">
  3. <el-select
  4. ref="treeSelect"
  5. v-model="valueId"
  6. style="width: 100%"
  7. :filterable="true"
  8. :clearable="true"
  9. :filter-method="selectFilterData"
  10. :placeholder="placeholder"
  11. @clear="clearHandle"
  12. >
  13. <el-option :value="valueId" :label="valueTitle">
  14. <el-tree
  15. id="tree-option"
  16. ref="selectTree"
  17. :accordion="accordion"
  18. :data="options"
  19. :props="objMap"
  20. :node-key="objMap.value"
  21. :expand-on-click-node="false"
  22. :default-expanded-keys="defaultExpandedKey"
  23. :filter-node-method="filterNode"
  24. @node-click="handleNodeClick"
  25. ></el-tree>
  26. </el-option>
  27. </el-select>
  28. </div>
  29. </template>
  30. <script setup lang="ts">
  31. interface ObjMap {
  32. value: string;
  33. label: string;
  34. children: string;
  35. }
  36. interface Props {
  37. objMap: ObjMap;
  38. accordion: boolean;
  39. value: string | number;
  40. options: any[];
  41. placeholder: string;
  42. }
  43. const props = withDefaults(defineProps<Props>(), {
  44. objMap: () => {
  45. return {
  46. value: 'id',
  47. label: 'label',
  48. children: 'children'
  49. };
  50. },
  51. accordion: false,
  52. value: '',
  53. options: () => [],
  54. placeholder: ''
  55. });
  56. const selectTree = ref<ElTreeSelectInstance>();
  57. const emit = defineEmits(['update:value']);
  58. const valueId = computed({
  59. get: () => props.value,
  60. set: (val) => {
  61. emit('update:value', val);
  62. }
  63. });
  64. const valueTitle = ref('');
  65. const defaultExpandedKey = ref<any[]>([]);
  66. const initHandle = () => {
  67. nextTick(() => {
  68. const selectedValue = valueId.value;
  69. if (selectedValue !== null && typeof selectedValue !== 'undefined') {
  70. const node = selectTree.value?.getNode(selectedValue);
  71. if (node) {
  72. valueTitle.value = node.data[props.objMap.label];
  73. selectTree.value?.setCurrentKey(selectedValue); // 设置默认选中
  74. defaultExpandedKey.value = [selectedValue]; // 设置默认展开
  75. }
  76. } else {
  77. clearHandle();
  78. }
  79. });
  80. };
  81. const handleNodeClick = (node: any) => {
  82. valueTitle.value = node[props.objMap.label];
  83. valueId.value = node[props.objMap.value];
  84. defaultExpandedKey.value = [];
  85. selectTree.value?.blur();
  86. selectFilterData('');
  87. };
  88. const selectFilterData = (val: any) => {
  89. selectTree.value?.filter(val);
  90. };
  91. const filterNode = (value: any, data: any) => {
  92. if (!value) return true;
  93. return data[props.objMap['label']].indexOf(value) !== -1;
  94. };
  95. const clearHandle = () => {
  96. valueTitle.value = '';
  97. valueId.value = '';
  98. defaultExpandedKey.value = [];
  99. clearSelected();
  100. };
  101. const clearSelected = () => {
  102. const allNode = document.querySelectorAll('#tree-option .el-tree-node');
  103. allNode.forEach((element) => element.classList.remove('is-current'));
  104. };
  105. onMounted(() => {
  106. initHandle();
  107. });
  108. watch(valueId, () => {
  109. initHandle();
  110. });
  111. </script>
  112. <style lang="scss" scoped>
  113. @import '@/assets/styles/variables.module.scss';
  114. .el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
  115. padding: 0;
  116. background-color: #fff;
  117. height: auto;
  118. }
  119. .el-select-dropdown__item.selected {
  120. font-weight: normal;
  121. }
  122. ul li .el-tree .el-tree-node__content {
  123. height: auto;
  124. padding: 0 20px;
  125. box-sizing: border-box;
  126. }
  127. :deep(.el-tree-node__content:hover),
  128. :deep(.el-tree-node__content:active),
  129. :deep(.is-current > div:first-child),
  130. :deep(.el-tree-node__content:focus) {
  131. background-color: mix(#fff, $--color-primary, 90%);
  132. color: $--color-primary;
  133. }
  134. </style>