Vue编写一个自己的树形组件

本文详细介绍了如何在Vue项目中不依赖组件库,自定义一个可扩展和样式定制的树形组件,包括父组件结构、节点组件的代码和使用示例,以及如何传递数据和处理节点点击事件。
摘要由CSDN通过智能技术生成

一、需求情况

        有时候用Vue开发的时候,不想使用组件库,但是遇到需要目录显示的情况的时候,想要一个树形递归的组件,可以自己封装定义想要的样式效果与事件,本文讲解如何实现一个自己的树形组件。

二、开发组件

Tree.vue父组件

<!--
 * @Author: 羊驼
 * @Date: 2024-03-04 11:43:47
 * @LastEditors: 羊驼
 * @LastEditTime: 2024-03-12 17:16:58
 * @Description: 树形组件的树
-->
<template>
  <ul>
    <tree-node
      v-for="node in nodes"
      :key="node.id"
      :node="node"
      :select_id="select_id"
      @node-clicked="handleNodeClicked"
    ></tree-node>
  </ul>
</template>
<script>
import TreeNode from "./TreeNode.vue";
export default {
  components: {
    TreeNode,
  },
  props: {
    // 节点数据
    nodes: Array,
    // 当前选中的节点
    select_id: String | Number,
  },
  methods: {
    // 定义一个节点点击事件
    handleNodeClicked(clickedNode) {
      this.$emit("node-clicked", clickedNode);
    },
  },
};
</script>

<style scoped>
ul {
  list-style: none;
}
</style>

TreeNode 节点组件

<!--
 * @Author: 羊驼
 * @Date: 2024-03-04 11:42:24
 * @LastEditors: 羊驼
 * @LastEditTime: 2024-03-12 17:19:30
 * @Description: 树形节点
-->
<template>
  <div>
    <li
      :class="{'a-selected':select_id==node.id}"
      class="flex"
      ref="text"
      @click="childClicked(node)"
    >
      <div
        class="icon-box"
        v-if="haveChild"
      >
        <svg
          @click="setExpanded(!isExpanded)"
          t="1709605135944"
          class="icon"
          viewBox="0 0 1024 1024"
          version="1.1"
          xmlns="http://www.w3.org/2000/svg"
          p-id="2647"
          width="25"
          height="25"
          :class="{rotate:isExpanded}"
          :fill="select_id==node.id?'#ccc':'#000'"
        >
          <path
            d="M500.8 604.779L267.307 371.392l-45.227 45.27 278.741 278.613L779.307 416.66l-45.248-45.248z"
            p-id="2648"
          ></path>
        </svg>
      </div>
      <span>{{node.name}}</span>
    </li>
    <ul v-if="haveChild&&isExpanded">
      <tree-node
        v-for="child in node.children"
        :key="child.id"
        :node="child"
        :select_id="select_id"
        @node-clicked="childClicked"
      ></tree-node>
    </ul>
  </div>
</template>

<script>
export default {
  // 因为是递归组件 导入的时候一定要以懒加载的形式 不然会报错的
  components: { "tree-node": () => import("./TreeNode.vue") },
  data() {
    return {
      // 展开情况
      isExpanded: false,
    };
  },
  props: {
    node: Object,
    select_id: String | Number,
  },
  computed: {
    // 判断是否可以展开
    haveChild() {
      return this.node.children && this.node.children.length;
    },
  },
  methods: {
    // 设置展开情况
    setExpanded(value) {
      this.isExpanded = value;
    },
    // 点击情况
    childClicked(clickedNode) {
      this.$emit("node-clicked", clickedNode);
    },
  },
};
</script>

<style scoped>
.icon-box {
  width: 40px !important;
  display: flex;
}
.icon {
  text-align: center;
  margin-right: 10px;
  transition: all 0.2s ease;
  transform: rotate(-90deg);
}
ul {
  list-style: none;
  padding-left: 20px !important;
}
.flex {
  display: flex;
  align-items: center;
  padding: 10px 20px;
  user-select: none;
}

.flex a {
  padding: 0 !important;
}

.flex:hover {
  background: #f2f9f5 !important;
  color: #008737 !important;
}

.flex:hover a {
  background: #f2f9f5 !important;
  color: #008737 !important;
}

.a-selected,
.a-selected a {
  background: #008737 !important;
  color: #fff !important;
}
.rotate {
  transform: rotate(0);
}
</style>

三、使用组件

<!--
 * @Author: 羊驼
 * @Date: 2024-03-12 16:49:46
 * @LastEditors: 羊驼
 * @LastEditTime: 2024-03-12 17:21:17
 * @Description: 示例
-->
<template>
  <div>
    <tree
      :nodes="nodes"
      :select_id="select_id"
      @node-clicked="handleNodeClicked"
    >
    </tree>
  </div>
</template>

<script>
import Tree from "./components/Tree.vue";
export default {
  // 组件引入
  components: { Tree },
  data() {
    return {
      // 测试数据
      nodes: [
        {
          id: 1,
          name: "测试1",
          children: [
            {
              id: 2,
              name: "测试1-1",
              children: [
                {
                  id: 3,
                  name: "测试2-1",
                },
              ],
            },
            {
              id: 4,
              name: "测试1-2",
            },
          ],
        },
        {
          id: 6,
          name: "测试2",
        },
      ],
      select_id: "",
    };
  },
  methods: {
    // 节点选中后
    handleNodeClicked(node) {
      this.select_id = node.id;
    },
  },
};
</script>

<style>
</style>

四、效果展示

最简版本 后续有什么需求 可以自己定义插槽和事件实现

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值