Vue 递归组件(构建树形菜单)

对于一些有规律的DOM结构,若是咱们再一遍遍的编写一样的代码,显然代码是比较繁琐和不科学的,并且本身的工做量会大大增长,git

那么有没有一种方法来解决这个问题呢?docker

答案是确定的,咱们能够经过 递归 方式来生成这个结构,固然在 Vue 模板中也是能够实现的,咱们能够在 Vue 的组件中调用本身自己,这样就能达到目的。bash

固然,在 Vue 中,组件能够递归的调用自己,可是有一些条件:架构

  • 该组件必定要有 name 属性
  • 要确保递归的调用有终止条件,防止内存溢出

为了方便理解递归组件,我写了一个小小的 Demo:组件化

下面有这样一个数据,咱们但愿把它作成一个文件树同样的结果:ui

treeData: {
        title: "Web全栈架构师",
        children: [
          {
            title: "Java架构师"
          },
          {
            title: "JS高级",
            children: [
              {
                title: "ES6"
              },
              {
                title: "动效"
              }
            ]
          },
          {
            title: "Web全栈",
            children: [
              {
                title: "Vue训练营",
                expand: true,
                children: [
                  {
                    title: "组件化"
                  },
                  {
                    title: "源码"
                  },
                  {
                    title: "docker部署"
                  }
                ]
              },
              {
                title: "React",
                children: [
                  {
                    title: "JSX"
                  },
                  {
                    title: "虚拟DOM"
                  }
                ]
              },
              {
                title: "Node"
              }
            ]
          }
        ]
      }
复制代码

先写一个树组件(Item):this

<template>
  <li>
    <!-- 点击折叠展开 -->
    <div @click="toggle">
      <!-- 显示内容 -->
      {{model.title}}
      <!-- 显示折叠展开的图标,若是没有下级目录的话,则不显示 -->
      <span v-if="isFolder">[{{open?'-':'+'}}]</span>
    </div>
    <!-- 控制是否显示下级目录 -->
    <ul v-show="open" v-if="isFolder">
      <!-- 重点代码,调用自身,实现递归,绑定数据 -->
      <Item v-for="model in model.children" :model="model" :key="model.title"></Item>
    </ul>
  </li>
</template>
<script>
export default {
  name: "Item",
  // 若是想使用此组件,则须要传递的数据
  props: {
    model: {
      type: Object,
      required: true
    }
  },
  data() {
    return {
      // 默认不显示下级目录
      open: false
    };
  },
  computed: {
    // 控制是否有下级目录和显示下级目录
    isFolder() {
      return this.model.children && this.model.children.length;
    }
  },
  methods: {
    // 点击折叠展开的方法
    toggle() {
      if (this.isFolder) {
        this.open = !this.open;
      }
    }
  }
};
</script>
复制代码

具体代码的功能已在上面注释spa

再次强调,这个组件必需要含有 name 这个属性,若是没有 name 这个属性会形成控件自身不能调用自身,并且调用的时候最好绑定一个 key 值,由于这个 key 值是惟一的标识code

另外须要注意,当递归组件的时候,须要有一个条件来终止递归,在这里使用 v-for 隐形条件终止递归component

而后在外部组件引入这个组件,并绑定数据使用,以下:

<template>
  <div>
    <ul>
      <!-- 使用这个组件,并绑定数据 -->
      <Item :model="treeData"></Item>
    </ul>
  </div>
</template>
<script>
// 导入递归组件
import Item from "./views/Item";
export default {
  name: "App",
  data() {
    return {
      // 须要实现递归的数据,上面已经给出
      treeData: {...
      }
    };
  },
  components: {
    // 注册组件
    Item
  }
};
</script>
复制代码

上面的代码已经实现了一个递归树形结构了,展现效果以下:

图片加载失败!

后面是 + 号 的能够点击展开,是 - 号 的能够点击折叠

虽然这篇博客看起来很简单,只是一个小的知识点,可是Vue的递归组件确实是一个很是强大的功能。能够用来实现一些相似文件树、部门树、级联选择这样的组件,在实际业务开发中这些组件也常常用到,仍是很是重要的~


^_<

相关文章
相关标签/搜索