treeList.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <template>
  2. <div class="vtl-node" :id="model.id" :class="{ 'vtl-leaf-node': !isFolder, 'vtl-tree-node': isFolder }">
  3. <div :class="treeNodeClass" @mouseover="mouseOver" @mouseout="mouseOut" @click.stop="toggle">
  4. <div class="vtl-border-text">
  5. <template v-if="isFolder">
  6. <slot v-if="expanded" :item="{ title: model.title, isFolder: true, expanded: true }" name="icon"> </slot>
  7. <slot v-else :item="{ title: model.title, isFolder: true, expanded: false }" name="icon"></slot>
  8. </template>
  9. <slot v-else :item="{ title: model.title, isFolder: false }" name="icon"></slot>
  10. <span class="vtl-node-content ellipsis">
  11. {{ model.title }}
  12. </span>
  13. </div>
  14. <div class="vtl-operation" v-show="isHover && !isFolder">
  15. <span @click.stop.prevent="delNode">
  16. <slot name="operation" type="detailNode"></slot>
  17. </span>
  18. </div>
  19. </div>
  20. </div>
  21. <div class="vtl-tree-margin" v-show="expanded">
  22. <!-- 这里无法使用$attr来透传属性官方还未解决此bug -->
  23. <treeList @on-click="(depth) => $emit('onClick', depth)" @detail-node="(depth) => $emit('detailNode', depth)"
  24. v-for="newmodel in model.children" :selected="selected" :model="newmodel" :key="newmodel.id">
  25. <template #icon="slotProps">
  26. <slot name="icon" v-bind="slotProps"></slot>
  27. </template>
  28. <template #operation="slotProps">
  29. <slot name="operation" v-bind="slotProps"></slot>
  30. </template>
  31. </treeList>
  32. </div>
  33. </template>
  34. <script setup lang="ts">
  35. import { computed, ref, } from 'vue';
  36. interface IFileSystem {
  37. id: string;
  38. title: string;
  39. pid: string;
  40. ppid: string,
  41. isFolder: boolean;
  42. isAdd: boolean;
  43. children?: IFileSystem[];
  44. }
  45. // 吐出去的事件
  46. const emit = defineEmits([
  47. 'onClick',
  48. 'detailNode',
  49. ]);
  50. // 拿到传入的值
  51. const props = withDefaults(
  52. defineProps<{
  53. model: IFileSystem;
  54. selected: IFileSystem;
  55. }>(),
  56. {
  57. // draggable: false,
  58. }
  59. );
  60. //是否移入
  61. const isHover = ref(false);
  62. // 是否展开
  63. const expanded = ref(true);
  64. // 是否是文件夹
  65. const isFolder = computed(() => {
  66. return props.model.isFolder;
  67. });
  68. const isSelected = computed(() => {
  69. if (props.model.pid == '0' || props.model.pid == '1' || props.model.pid == '2') {
  70. return props.selected.id === props.model.id && props.selected.pid === props.model.pid;
  71. } else if (props.model.ppid == '0' || props.model.ppid == '1' || props.model.ppid == '2') {
  72. return props.selected.id === props.model.id && props.selected.ppid === props.model.ppid;
  73. } else {
  74. return props.selected.id === props.model.id ;
  75. }
  76. })
  77. // 拖拽样式
  78. const treeNodeClass = computed(() => {
  79. return {
  80. 'vtl-node-main': true,
  81. selected: isSelected.value,
  82. };
  83. });
  84. // 删除目录
  85. const delNode = () => {
  86. emit('detailNode', {
  87. ...props.model,
  88. eventType: 'detail',
  89. });
  90. };
  91. // 展开收起
  92. const toggle = () => {
  93. if (isFolder.value) {
  94. console.log(props.model, 'props.model---------')
  95. expanded.value = !expanded.value;
  96. emit('onClick', {
  97. ...props.model,
  98. }); //lxh
  99. } else {
  100. console.log(props.model, 'props.model---------')
  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>