当前位置: 代码网 > it编程>前端脚本>Vue.js > Vue3 通过作用域插槽实现树形菜单嵌套组件

Vue3 通过作用域插槽实现树形菜单嵌套组件

2024年05月19日 Vue.js 我要评论
一、需求来源工作中需要一种树形菜单组件,经过两天的构思最终通过作用域插槽实现: 此组件将每个节点(插槽名为 node)暴露出来。通过插槽的 attributes 向当前插槽节点传递子项 item(数据

一、需求来源

工作中需要一种树形菜单组件,经过两天的构思最终通过作用域插槽实现: 此组件将每个节点(插槽名为 node)暴露出来。

通过插槽的 attributes 向当前插槽节点传递子项 item(数据对象)和level(层深)参数,在保持组件内部极简的同时支持在数据模型中扩展性。基本达到比较好的封装颗粒度,大家可以在此基础上无限扩展封装具体的业务逻辑。

二、效果图

let list = reactive(
  [{ 
    name:'1 一级菜单',
    isexpand: true,//是否展开子项
    enabled: false,//是否可以响应事件
    child:[
      { name:'1.1 二级菜单',     
        isexpand: true,
        child:[
          { name:'1.1.1 三级菜单', isexpand: true, },
        ]
      },
      { name:'1.2 二级菜单', isexpand: true, },
    ]
  },
  { 
    name:'1.1 一级菜单',
    isexpand: true,
    child:[
      { name:'1.1.1 二级菜单', isexpand: true, },
      { name:'1.1.2 二级菜单', 
        isexpand: false, 
        child:[
          { name:'1.1.2.1 三级菜单', isexpand: true, },
        ]},
    ]
  },]
);

三、使用示例(vtreenodedemo.vue)

<template>
  <vtreenode 
    :list="list"
    :level="level"
  >
    <template #node="slotprops">
      <div class="tree-node">
        {{prefix(slotprops.level)}}{{slotprops.item.name}}{{sufix(slotprops.item)}}
      </div>
    </template>
  </vtreenode>
</template>
<script setup>
import vtreenode from '@/components/vtreenode/vtreenode.vue';
import { ref, reactive, watch, onmounted, } from 'vue';
let list = reactive(
  [{ 
    name:'1 一级菜单',
    isexpand: true,//是否展开子项
    enabled: false,//是否可以响应事件
    child:[
      { name:'1.1 二级菜单',     
        isexpand: true,
        child:[
          { name:'1.1.1 三级菜单', isexpand: true, },
        ]
      },
      { name:'1.2 二级菜单', isexpand: true, },
    ]
  },
  { 
    name:'1.1 一级菜单',
    isexpand: true,
    child:[
      { name:'1.1.1 二级菜单', isexpand: true, },
      { name:'1.1.2 二级菜单', 
        isexpand: false, 
        child:[
          { name:'1.1.2.1 三级菜单', isexpand: true, },
        ]},
    ]
  },]
);
const level = ref(0);
const prefix = (count) => {
  return '__'.repeat(count);
};
const sufix = (item) => {
  if (!reflect.has(item, 'child')) {
    return '';
  }
  return ` (${item.child.length}子项)`;
};
</script>
<style scoped lang='scss'>
.tree-node{
  height: 45px;
  display: flex;
  justify-self: center;
  align-items: center;
  // background-color: green;
  border-bottom: 1px solid #e4e4e4;
}
</style>

四、源码(vtreenode.vue):

<template>
  <!-- <div> -->
    <div v-for="(item,index) in list" :key="index">
      <slot name="node" :item="item" :level="levelref">
        <div>{{ item.name }}</div>
      </slot>
      <div v-show="item.child && canexpand(item)" >
        <vtreenode :list="item.child" :level="levelref">
          <template #node="slotprops">
            <slot name="node" :item="slotprops.item" :level="slotprops.level">
              <div>{{ slotprops.item.name }}</div>
            </slot>
          </template>
        </vtreenode>
      </div>
    </div>
  <!-- </div> -->
</template>
<script setup>
import { ref, reactive, watch, computed, onmounted, } from 'vue';
const props = defineprops({
  list: {
    type: array,
    default: () => [],
    validator: (val) => {
      return array.isarray(val) && val.every(e => reflect.has(e, 'name'));
    }
  },
  level: {
    type: number,
    default: 0,
  }
});
const emit = defineemits(['update:level', ])
const levelref = computed({
  set: (newval) => {
    if (props.level !== newval) {
      emit("update:level", newval);
    }
  },
  get: () => {
    const tmp = props.level + 1;
    return tmp;
  },
});
const canexpand = (item) => {
  return reflect.has(item, 'isexpand') && item.isexpand;
};
// onmounted(() => {
//   console.log(`levelref:${levelref.value}`);
// });
</script>

vtreenode.vue

vtreenodedemo.vue

以上就是vue3 通过作用域插槽实现树形菜单/嵌套组件的详细内容,更多关于vue3 树形菜单嵌套组件的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com