treeList.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <template>
  2. <div class="vtl-node" :id="model.id" :class="{ 'vtl-leaf-node': !isFolder, 'vtl-tree-node': isFolder }">
  3. <div
  4. :class="treeNodeClass"
  5. @mouseover="mouseOver"
  6. @mouseout="mouseOut"
  7. @click.stop="toggle"
  8. >
  9. <div class="vtl-border-text">
  10. <template v-if="isFolder">
  11. <slot v-if="expanded" :item="{ title: model.title, isFolder: true, expanded: true }" name="icon"> </slot>
  12. <slot v-else :item="{ title: model.title, isFolder: true, expanded: false }" name="icon"></slot>
  13. </template>
  14. <slot v-else :item="{ title: model.title, isFolder: false }" name="icon"></slot>
  15. <span class="vtl-node-content ellipsis" >
  16. {{ model.title }}
  17. </span>
  18. </div>
  19. <div class="vtl-operation" v-show="isHover && !isFolder">
  20. <span @click.stop.prevent="delNode">
  21. <slot name="operation" type="deleteNode"></slot>
  22. </span>
  23. </div>
  24. </div>
  25. </div>
  26. <div class="vtl-tree-margin" v-show="expanded" v-if="isFolder">
  27. <!-- 这里无法使用$attr来透传属性官方还未解决此bug -->
  28. <treeList
  29. @on-click="(depth) => $emit('onClick', depth)"
  30. @delete-node="(depth) => $emit('deleteNode', depth)"
  31. v-for="newmodel in model.children"
  32. :selected="selected"
  33. :model="newmodel"
  34. :key="newmodel.id"
  35. >
  36. <template #icon="slotProps">
  37. <slot name="icon" v-bind="slotProps"></slot>
  38. </template>
  39. <template #operation="slotProps">
  40. <slot name="operation" v-bind="slotProps"></slot>
  41. </template>
  42. </treeList>
  43. </div>
  44. </template>
  45. <script setup lang="ts">
  46. import { computed, ref, } from 'vue';
  47. interface IFileSystem {
  48. id: string;
  49. title: string;
  50. pid: string;
  51. isFolder: boolean;
  52. isAdd: boolean;
  53. children?: IFileSystem[];
  54. }
  55. // 吐出去的事件
  56. const emit = defineEmits([
  57. 'onClick',
  58. 'deleteNode',
  59. ]);
  60. // 拿到传入的值
  61. const props = withDefaults(
  62. defineProps<{
  63. model: IFileSystem;
  64. selected: IFileSystem;
  65. }>(),
  66. {
  67. // draggable: false,
  68. }
  69. );
  70. //是否移入
  71. const isHover = ref(false);
  72. // 是否展开
  73. const expanded = ref(true);
  74. // 是否是文件夹
  75. const isFolder = computed(() => {
  76. return props.model.isFolder;
  77. });
  78. const isSelected = computed(() => props.selected.id === props.model.id);
  79. // 拖拽样式
  80. const treeNodeClass = computed(() => {
  81. return {
  82. 'vtl-node-main': true,
  83. selected: isSelected.value,
  84. };
  85. });
  86. // 删除目录
  87. const delNode = () => {
  88. emit('deleteNode', {
  89. ...props.model,
  90. eventType: 'delete',
  91. });
  92. };
  93. // 展开收起
  94. const toggle = () => {
  95. if (isFolder.value) {
  96. expanded.value = !expanded.value;
  97. emit('onClick', {
  98. ...props.model,
  99. }); //lxh
  100. } else {
  101. emit('onClick', {
  102. ...props.model,
  103. });
  104. }
  105. };
  106. // 拖拽结束
  107. const mouseOver = () => {
  108. isHover.value = true;
  109. };
  110. // 移出
  111. const mouseOut = () => {
  112. isHover.value = false;
  113. };
  114. </script>
  115. <style lang="less">
  116. .vtl-node {
  117. .vtl-node-main {
  118. display: flex;
  119. align-items: center;
  120. padding: 2px 0 2px 2px;
  121. cursor: pointer;
  122. &:hover {
  123. .vtl-border-text {
  124. width: 80%;
  125. }
  126. }
  127. .vtl-border-text {
  128. display: flex; //lxh
  129. flex: 1;
  130. align-items: center; //lxh
  131. width: 100%;
  132. padding-left: 5px;
  133. .iconfont {
  134. width: 16px;
  135. height: 16px;
  136. vertical-align: text-bottom;
  137. }
  138. }
  139. &.selected {
  140. // background-color: rgba(45, 113, 134, 0.2);
  141. background-color: #1c4869;
  142. }
  143. .vtl-node-content {
  144. color: #fff;
  145. padding-left: 5px;
  146. font-size: 14px;
  147. width: 80%;
  148. display: inline-block;
  149. vertical-align: bottom;
  150. }
  151. &:hover {
  152. .vtl-node-content {
  153. color: #fff;
  154. overflow: hidden;
  155. }
  156. }
  157. .vtl-operation {
  158. padding-right: 10px;
  159. }
  160. }
  161. }
  162. .vtl-tree-margin {
  163. padding-left: 1em;
  164. }
  165. </style>