• vue 做一个树图


    之前想着做一个树图,通过v-for套3层,实现了一个三层树图

     后来突然开窍了,vue组件的形式,可以组件套组件,方便多了

    仿windows文件管理器的文件树

    先上图

    定义数据结构

    [

            {

                    "path":"/快速访问",

                    "name":"快速访问",

                    "icon":"quick_access",

                    "type":"dir",

                    "child":[]

            },

    ]

    通过child无线嵌套。

    基础结构

    当前节点中包含,展开图标,合并图标,空白图标,文件夹图标,文件名。

    子节点就是遍历当前节点的child数组生成。

    需要注意两个问题

    (1)树图不是一下子就把全部叶子节点都给展开的,未展开前,需不需要提前渲染好。

    (2)叶子节点多次展开合并,子节点不应该每次都重复生成渲染。

    这里使用两个变量来控制。

    isExtend: false, 是否展开节点,通过v-show开控制
    isCreatedChild: false,是否生成节点,通过v-if来控制

    当第一次展开的时候,生成一次子节点。isCreatedChild变为true,后续不在变动。

    后续展开合并通过控制isExtend即可。

    这样也是实现了异步加载树节点。

    无子节点的情况

    添加如下变量,默认为true

    isExistChild: true,

    在第一次展开的时候判断一次,没有子节点时置为false,后续不在改动

    当isExistChild为false时,将展开合并图标隐藏,不显示。

    设置选中样式

    如何实现只选中一个节点?

    设置选中和未选中的样式

    1. .file_tree_node_div {
    2. white-space: nowrap;
    3. border: 1px solid transparent;
    4. }
    5. .file_tree_node_div:hover {
    6. background-color: #e9f3f3;
    7. border: 1px solid #e9f3f3;
    8. }
    9. .file_tree_node_div_selected {
    10. white-space: nowrap;
    11. background-color: #cce6ee;
    12. border: 1px solid #cce6ee;
    13. }
    14. .file_tree_node_div_selected:hover {
    15. border: 1px solid #b3dce7;
    16. }

    节点个数不固定,隔代节点之间通信困难,当点击一个节点标记为选中,遍历其他节点,将选中的置为不选中,这种消耗太大。

    不如直接操作document来的快,

    1. setSelected(){
    2. let arr=document.getElementsByClassName("file_tree_node_div_selected");
    3. if(arr&&arr.length>0)arr[0].className='file_tree_node_div';
    4. this.$refs.node.className='file_tree_node_div_selected';
    5. },

    完整效果

    附:节点源码

    1. <template>
    2. <div>
    3. <div ref="node" class="file_tree_node_div" >
    4. <b-icon v-if="isExistChild&&!isExtend" @click="handle_extend_node()" class="file_tree_node_arrow"
    5. local="arrow_thick_right" style="color: #adadad;">b-icon>
    6. <b-icon v-else-if="isExistChild&&isExtend" @click="handle_extend_node()" class="file_tree_node_arrow"
    7. local="arrow_thick_bottom" style="color: #535353;">b-icon>
    8. <img v-else class="file_tree_node_arrow" src="" style="opacity: 0;">
    9. <img class="file_tree_node_icon" :src="icon">
    10. <button class="empty_button file_tree_node_name" @click="handle_change_path">{{ name }}button>
    11. div>
    12. <div v-if="isCreatedChild" v-show="isExtend">
    13. <template v-for="(item,index) in child" :key="index+'b'">
    14. <FileTreeNode v-if="item.type==='dir'" :data="item" style="margin-left: 10px;">FileTreeNode>
    15. template>
    16. div>
    17. div>
    18. template>
    19. <script>
    20. export default {
    21. name: "FileTreeNode",
    22. props: {
    23. data: Object,
    24. },
    25. data() {
    26. return {
    27. name: '',
    28. icon: '',
    29. isExistChild: true,
    30. isExtend: false,
    31. isCreatedChild: false,
    32. isSelected:false,
    33. child: [],
    34. }
    35. },
    36. created() {
    37. this.init(this.data);
    38. },
    39. methods: {
    40. init(data) {
    41. if (data) {
    42. this.name = data.name;
    43. if (!data.icon || data.icon === '') this.icon = require("@/assets/file/dir.png")
    44. this.icon = require("@/assets/file/" + data.icon+'.png');
    45. this.child = data.child;
    46. this.path = data.path;
    47. if(data.isExtend)this.handle_extend_node();
    48. }
    49. },
    50. /**
    51. * 展开节点或者关闭节点
    52. */
    53. handle_extend_node() {
    54. this.isExistChild = this.checkExistDir(this.child);
    55. this.isExtend = !this.isExtend;
    56. if (!this.isCreatedChild) {
    57. this.isCreatedChild = true;
    58. }
    59. },
    60. /**
    61. * 检查路径下是否存在文件夹
    62. */
    63. checkExistDir(child) {
    64. if (child) {
    65. for (let i = 0; i < child.length; i++) {
    66. if (child[i].type === 'dir') return true;
    67. }
    68. }
    69. return false;
    70. },
    71. /**
    72. * 获取当前节点路径,每一个节点都将数组传递给父节点,等父节点添加好文件夹名称后,子节点在添加
    73. */
    74. getPath(arr){
    75. this.$parent.getPath(arr);
    76. if(!this.$parent.isRoot){
    77. arr.push(this.name);
    78. }
    79. return arr;
    80. },
    81. /**
    82. * 点击树图节点
    83. */
    84. handle_change_path(){
    85. if(this.$refs.node.className!=='file_tree_node_div_selected')
    86. this.setSelected();
    87. let path=[];
    88. if('此电脑 快速访问'.indexOf(this.name)>-1){
    89. path.push(this.name);
    90. }else{
    91. path=this.getPath([]);
    92. }
    93. this.$event.$emit('FileManager_set_data',path);
    94. },
    95. setSelected(){
    96. let arr=document.getElementsByClassName("file_tree_node_div_selected");
    97. if(arr&&arr.length>0)arr[0].className='file_tree_node_div';
    98. this.$refs.node.className='file_tree_node_div_selected';
    99. },
    100. },
    101. }
    102. script>
    103. <style>
    104. .file_tree_node_arrow {
    105. width: 25px;
    106. height: 25px;
    107. opacity: 0;
    108. transition: all 2s ease-out;
    109. }
    110. .file_tree_node_icon {
    111. width: 25px;
    112. height: 25px;
    113. margin-top: -4px;
    114. padding: 2px;
    115. }
    116. .file_tree_node_div {
    117. white-space: nowrap;
    118. border: 1px solid transparent;
    119. }
    120. .file_tree_node_div:hover {
    121. background-color: #e9f3f3;
    122. border: 1px solid #e9f3f3;
    123. }
    124. .file_tree_node_div_selected {
    125. white-space: nowrap;
    126. background-color: #cce6ee;
    127. border: 1px solid #cce6ee;
    128. }
    129. .file_tree_node_div_selected:hover {
    130. border: 1px solid #b3dce7;
    131. }
    132. .file_tree_node_name {
    133. padding-top: 2px;
    134. padding-left: 3px;
    135. cursor: pointer;
    136. }
    137. style>

  • 相关阅读:
    103.36.167.X在服务器删除、复制文件的时候会出现卡的情况,是什么原因?
    Nacos注册中心有几种调用方式?
    数据分析 -- numpy
    【MATLAB】字体美化和乱码
    SAP ABAP OData 服务如何支持删除(Delete)操作试读版
    2023年【危险化学品经营单位安全管理人员】考试资料及危险化学品经营单位安全管理人员考试试卷
    IT人必看 | 2022年春招市场行情报告——高薪职业榜首是这些!
    实验(六):定时器实验
    vue3的宏到底是什么东西?
    Springboot给每个接口设置traceId,并添加到返回结果中
  • 原文地址:https://blog.csdn.net/qq_43319748/article/details/126818397