treeList.vue 4.8 KB

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