当前位置:首页 > VUE

vue实现树形菜单组件

2026-02-21 15:08:48VUE

Vue 树形菜单组件实现方法

递归组件实现基础树形结构

使用 Vue 的递归组件特性可以轻松实现树形菜单。需要定义一个能够调用自身的组件。

<template>
  <ul>
    <li v-for="item in treeData" :key="item.id">
      {{ item.label }}
      <tree-menu 
        v-if="item.children && item.children.length" 
        :treeData="item.children"
      />
    </li>
  </ul>
</template>

<script>
export default {
  name: 'TreeMenu',
  props: {
    treeData: {
      type: Array,
      required: true
    }
  }
}
</script>

添加展开/折叠功能

通过添加一个 isOpen 状态来控制子菜单的显示与隐藏。

vue实现树形菜单组件

<template>
  <ul>
    <li v-for="item in treeData" :key="item.id">
      <span @click="toggle(item)">
        {{ item.label }}
        <span v-if="item.children && item.children.length">
          {{ item.isOpen ? '[-]' : '[+]' }}
        </span>
      </span>
      <tree-menu 
        v-if="item.children && item.children.length && item.isOpen" 
        :treeData="item.children"
        @toggle="toggle"
      />
    </li>
  </ul>
</template>

<script>
export default {
  name: 'TreeMenu',
  props: {
    treeData: {
      type: Array,
      required: true
    }
  },
  methods: {
    toggle(item) {
      this.$emit('toggle', item)
    }
  }
}
</script>

添加选中状态

在树形菜单中实现单选或多选功能。

<template>
  <ul>
    <li 
      v-for="item in treeData" 
      :key="item.id"
      :class="{ 'selected': item.isSelected }"
      @click="selectItem(item)"
    >
      <span @click.stop="toggle(item)">
        {{ item.label }}
        <span v-if="item.children && item.children.length">
          {{ item.isOpen ? '[-]' : '[+]' }}
        </span>
      </span>
      <tree-menu 
        v-if="item.children && item.children.length && item.isOpen" 
        :treeData="item.children"
        @toggle="toggle"
        @select="selectItem"
      />
    </li>
  </ul>
</template>

<script>
export default {
  name: 'TreeMenu',
  props: {
    treeData: {
      type: Array,
      required: true
    }
  },
  methods: {
    toggle(item) {
      this.$emit('toggle', item)
    },
    selectItem(item) {
      this.$emit('select', item)
    }
  }
}
</script>

<style>
.selected {
  background-color: #f0f0f0;
}
</style>

动态加载数据

对于大型树形结构,可以实现按需加载子节点数据。

vue实现树形菜单组件

<template>
  <ul>
    <li v-for="item in treeData" :key="item.id">
      <span @click="toggle(item)">
        {{ item.label }}
        <span v-if="item.hasChildren && !item.children">
          [>]
        </span>
        <span v-else-if="item.children && item.children.length">
          {{ item.isOpen ? '[-]' : '[+]' }}
        </span>
      </span>
      <tree-menu 
        v-if="item.children && item.children.length && item.isOpen" 
        :treeData="item.children"
        @toggle="toggle"
        @load="loadChildren"
      />
    </li>
  </ul>
</template>

<script>
export default {
  name: 'TreeMenu',
  props: {
    treeData: {
      type: Array,
      required: true
    }
  },
  methods: {
    toggle(item) {
      if (item.hasChildren && !item.children) {
        this.$emit('load', item)
      } else {
        this.$emit('toggle', item)
      }
    }
  }
}
</script>

添加拖拽功能

实现树形菜单节点的拖拽排序功能。

<template>
  <ul>
    <li 
      v-for="item in treeData" 
      :key="item.id"
      draggable="true"
      @dragstart="dragStart(item)"
      @dragover.prevent
      @drop="drop(item)"
    >
      <span @click="toggle(item)">
        {{ item.label }}
        <span v-if="item.children && item.children.length">
          {{ item.isOpen ? '[-]' : '[+]' }}
        </span>
      </span>
      <tree-menu 
        v-if="item.children && item.children.length && item.isOpen" 
        :treeData="item.children"
        @toggle="toggle"
        @dragStart="dragStart"
        @drop="drop"
      />
    </li>
  </ul>
</template>

<script>
export default {
  name: 'TreeMenu',
  props: {
    treeData: {
      type: Array,
      required: true
    }
  },
  data() {
    return {
      draggedItem: null
    }
  },
  methods: {
    toggle(item) {
      this.$emit('toggle', item)
    },
    dragStart(item) {
      this.draggedItem = item
    },
    drop(targetItem) {
      if (this.draggedItem !== targetItem) {
        this.$emit('drop', { draggedItem: this.draggedItem, targetItem })
      }
    }
  }
}
</script>

优化树形菜单性能

对于大型树形结构,可以使用虚拟滚动来提高性能。

<template>
  <div class="tree-container">
    <div 
      v-for="item in visibleItems" 
      :key="item.id"
      :style="{ paddingLeft: `${item.level * 20}px` }"
    >
      <span @click="toggle(item)">
        {{ item.label }}
        <span v-if="item.hasChildren">
          {{ item.isOpen ? '[-]' : '[+]' }}
        </span>
      </span>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    treeData: {
      type: Array,
      required: true
    }
  },
  computed: {
    visibleItems() {
      // 实现扁平化处理,只计算当前可见的节点
      return this.flattenTree(this.treeData)
    }
  },
  methods: {
    flattenTree(nodes, level = 0, result = []) {
      nodes.forEach(node => {
        result.push({ ...node, level })
        if (node.isOpen && node.children) {
          this.flattenTree(node.children, level + 1, result)
        }
      })
      return result
    },
    toggle(item) {
      this.$emit('toggle', item)
    }
  }
}
</script>

<style>
.tree-container {
  height: 500px;
  overflow-y: auto;
}
</style>

标签: 组件菜单
分享给朋友:

相关文章

vue实现组件循环图片

vue实现组件循环图片

Vue 中实现组件循环图片的方法 在 Vue 中,可以通过 v-for 指令循环渲染图片组件。假设有一组图片数据需要循环展示,可以采用以下方式: 数据准备 在组件的 data 或 props 中定…

css制作二级菜单

css制作二级菜单

使用纯CSS制作二级菜单 通过CSS的:hover伪类和子选择器实现二级菜单的显示与隐藏。以下是一个典型的结构和样式示例: HTML结构 <nav class="menu">…

纯css制作tab菜单

纯css制作tab菜单

纯CSS制作Tab菜单的方法 使用radio input控制切换 通过<input type="radio">和<label>元素配合实现无JavaScript的Tab切换效果…

uniapp如何将底部导航组件化

uniapp如何将底部导航组件化

在 uniapp 中将底部导航组件化 将底部导航组件化可以提高代码复用性和维护性。以下是具体实现方法: 创建自定义底部导航组件 新建一个组件文件,例如 tab-bar.vue,放置在 compon…

vue实现组件跟随

vue实现组件跟随

Vue 实现组件跟随效果 实现组件跟随效果通常需要监听鼠标或触摸事件,动态更新组件位置。以下是几种常见实现方式: 使用鼠标事件绑定 <template> <div class…

vue实现广告组件

vue实现广告组件

vue实现广告组件的方法 使用动态组件实现 在Vue中可以通过动态组件的方式加载广告组件,根据不同的条件展示不同的广告内容。动态组件使用<component :is="currentCompon…