vue自定义折叠Tree,自定义折叠树

使用组件

html 复制代码
<TreeNode v-for="(node, index) in nodes" :key="index" :node="node" />

JSON数据

javascript 复制代码
let nodes=[
    {
        "id": 2030,
        "show_id": "MC1813024492270223360",
        "detail_type": 1,
        "title": "1",
        "description": "",
        "class_hour": 10,
        "children": [
            {
                "id": 2031,
                "show_id": "MC1813024625619734528",
                "detail_type": 1,
                "title": "2",
                "description": "",
                "class_hour": 2,
                "children": [
                    {
                        "id": 1940,
                        "show_id": "MC1813024654644314112",
                        "detail_type": 2,
                        "title": "31",
                        "description": "我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介我是课程视频简介",
                        "class_hour": 0,
                        "children": null,
                        "study_status_str": "未学习",
                        "lesson_number": 0,
                        "level": 3
                    }
                ],
                "study_status_str": "",
                "lesson_number": 0,
                "level": 2
            }
        ],
        "study_status_str": "",
        "lesson_number": 1,
        "level": 1
    }
]

组件

html 复制代码
<template>
  <div :style="{ paddingLeft: level * 20 + 'px' }" class="tree-node">
    <div
      @click="toggle"
      class="tree-node-header"
      :class="{ 'first-level': node.level == 1 }"
    >
      <img :src="node.level == 1 ? imgs.group : imgs.dot" alt="" />
      <span class="title">{{ node.title }}</span>
      <template v-if="node.level == 1">
        <span class="class-hour all-hour">总学时 {{ node.class_hour }}</span>
        <span class="class-hour">视频课{{ node.lesson_number }}</span>
      </template>
      <template v-if="!node.children && node.detail_type == 2">
        <span @click="handleClassHour(node)" class="class-hour play"
          ><i class="iconfont">&#xe648;</i>视频课</span
        >
        <!-- <span class="class-hour schedule" >已学习&nbsp;&nbsp;{{ '100%' }}</span> -->
        <span class="class-hour schedule">{{ node.study_status_str }}</span>
      </template>
      <span v-if="hasChildren" class="arrow">
        <i v-show="isOpen" class="el-icon-arrow-up" />
        <i v-show="!isOpen" class="el-icon-arrow-down" />
        <!-- {{ isOpen ? "-" : "+" }} -->
      </span>
    </div>
    <div class="content" v-if="!node.children && node.level != 1">
      {{ node.description }}
    </div>
    <transition name="expand">
      <div v-if="isOpen" class="tree-node-children">
        <TreeNode
          v-for="(child, index) in node.children"
          :key="index"
          :node="child"
          :level="level + 1"
        />
      </div>
    </transition>
  </div>
</template>

<script>
export default {
  name: "TreeNode",
  props: {
    node: {
      type: Object,
      required: true,
    },
    level: {
      type: Number,
      default: 1,
    },
  },
  data() {
    return {
      isOpen: false,
      imgs: {
        group: require("@/pages/web_site_front/resource_manage/pages/onlineCourses/assets/group.png"),
        dot: require("@/pages/web_site_front/resource_manage/pages/onlineCourses/assets/dot.png"),
      },
    };
  },
  computed: {
    hasChildren() {
      return (this.node.children && this.node.children?.length) || 0;
    },
  },
  methods: {
    toggle() {
      if (this.hasChildren) {
        this.isOpen = !this.isOpen;
      }
    },
    handleClassHour(node) {
      document.querySelector(".main-content").scrollTop = 0;
      this.$store.dispatch("user/setCourseVideoId", node.id);
    },
  },
  components: {
    TreeNode: () => import("./treeNode.vue"),
  },
};
</script>

<style scoped lang="scss">
.tree-node {
  margin: 5px 0;
  .tree-node-header {
    cursor: pointer;
    padding: 5px;
    margin-bottom: 16px;
    display: flex;
    font-weight: bold;

    img {
      width: 10px;
      align-self: center;
      margin: 0 5px;
    }
    .title {
      max-width: calc(100% - 160px);
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }
    .play {
      font-size: 12px;
      color: #00ab6b;
      line-height: 20px;
      height: 20px;
      border: 0.5px solid #c3e7da;
      border-radius: 4px;
      padding: 0 4px;
      margin-left: 8px;
      display: inline-table;

      i {
        font-size: 14px;
        margin-right: 4px;
      }
    }
    .schedule {
      font-size: 12px;
      color: #00000040;
      margin-left: 8px;
    }
    .arrow {
      flex: 1;
      text-align: right;
      color: #00ab6b;
      margin-right: 31px;
    }
  }
  .first-level {
    height: 40px;
    line-height: 40px;
    display: flex;
    margin-bottom: 16px;
    background: #fafafa;
    border-radius: 8px;
    font-weight: bold;
    font-size: 16px;
    span {
      align-self: center;
    }
    img {
      width: 30px;
      align-self: center;
    }
    .class-hour {
      color: #000000a6;
      line-height: 22px;
      padding: 0 8px;
      background: #f5f5f5;
      border-radius: 2px;
      margin-right: 6px;
      font-size: 14px;
    }
    .all-hour {
      margin-left: 26px;
    }
  }
  .content {
    color: #00000073;
    line-height: 22px;
    border-bottom: 1px solid #f0f0f0;
    padding-bottom: 16px;
    margin-left: 26px;
  }
}

.tree-node-children {
  margin-top: 5px;
  //   border-left: 2px solid #ccc;
  padding-left: 0px;
  .tree-node{
    padding-left: 20px !important;
  }
}

/* Animation Styles */
.expand-enter-active,
.expand-leave-active {
  transition: all 0.3s ease;
}

.expand-enter, .expand-leave-to /* .expand-leave-active in <2.1.8 */ {
  height: 0;
  opacity: 0;
  overflow: hidden;
}
</style>
相关推荐
xing25163 分钟前
pytest-html
前端·html·pytest
茂茂在长安13 分钟前
Linux 命令大全完整版(11)
java·linux·运维·服务器·前端·centos
Violet51514 分钟前
ECMAScript规范解读——this的判定
javascript
知识分享小能手1 小时前
Html5学习教程,从入门到精通,HTML5 简介语法知识点及案例代码(1)
开发语言·前端·javascript·学习·前端框架·html·html5
IT、木易1 小时前
大白话React第二章深入理解阶段
前端·javascript·react.js
晚安7201 小时前
Ajax相关
前端·javascript·ajax
图书馆钉子户1 小时前
怎么使用ajax实现局部刷新
前端·ajax·okhttp
bin91531 小时前
DeepSeek 助力 Vue 开发:打造丝滑的单选按钮(Radio Button)
前端·javascript·vue.js·ecmascript·deepseek
qianmoQ1 小时前
第五章:工程化实践 - 第五节 - Tailwind CSS 常见问题解决方案
前端·css
那就可爱多一点点1 小时前
超高清大图渲染性能优化实战:从页面卡死到流畅加载
前端·javascript·性能优化