您的位置:首页 > 教程 > JavaScript > Vue3 通过作用域插槽实现树形菜单嵌套组件

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

2023-01-20 09:49:32 来源:易采站长站 作者:

目录
一、需求来源二、效果图三、使用示例(VTreeNodeDemo.vue)四、源码(VTreeNode.vue):

一、需求来源

工作中需要一种树形菜单组件,经过两天的构思最终通过作用域插槽实现:>

通过插槽的 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 树形菜单嵌套组件的资料请关注易采站长站其它相关文章!

如有侵权,请发邮件到 [email protected]

相关文章

  • vue跳转页面的几种方法(推荐)

    vue跳转页面的几种方法(推荐)

    vue跳转不同页面的多种方法 1:router-link跳转 !-- 直接跳转 --router-link to='/testDemo' button点击跳转2/button/router-link !-- 带参数跳转 --router-link :to="{path:'testDemo',query:{setid:123456}}" button点击跳转
    2020-03-26
  • Vue+elementUI实现多图片上传与回显功能(含回显后继续上传或删除

    Vue+elementUI实现多图片上传与回显功能(含回显后继续上传或删除

    最近有使用vue+elementUI实现多图片上传的需求,遂做此纪录。 本次主要写一下前端的实现细节,至于后台以Multipart[ ]数组接收即可,不再赘述,网上一搜大把文章可供参考。 本次使用
    2020-03-23
  • 微信小程序搜索框样式并实现跳转到搜索页面(小程序搜索功能

    微信小程序搜索框样式并实现跳转到搜索页面(小程序搜索功能

    上效果图: 一:搜索框功能实现 1.在首页做一个搜索框的样式并实现跳转到搜索页面 view class='page_row' bindtap="suo" view class="search" view class="df search_arr" icon class="searchcion" size='20' type='search'/
    2020-03-10
  • 微信小程序实现canvas分享朋友圈海报

    微信小程序实现canvas分享朋友圈海报

    本文实例为大家分享了微信小程序分享朋友圈海报的具体代码,供大家参考,具体内容如下 思路:生成朋友圈海报放在公共文件,首先需要绘制canvas,点击分享朋友圈按钮,在手机屏幕
    2020-06-21
  • 详解ES6 Modules

    详解ES6 Modules

    当下, 我们几乎所有的项目都是基于 webpack、rollup 等构建工具进行开发的,模块化已经是常态。 我们对它并不陌生,今天,我们就再系统的回顾一下ES6的模块机制, 并总结下常用的操
    2020-07-04
  • Vue-router 报错NavigationDuplicated的解决方法

    Vue-router 报错NavigationDuplicated的解决方法

    版本:3.1.x 报错原因: 使用push()、replace()进行导航时,不能重复导航到当前路由。 解决办法: 方法1:在定义路由的文件中router/index.js const originalPush = VueRouter.prototype.pushVueRouter.protot
    2020-03-31
  • vue使用better-scroll实现滑动以及左右联动

    vue使用better-scroll实现滑动以及左右联动

    本文实例为大家分享了vue实现滑动以及左右联动效果的具体代码,供大家参考,具体内容如下 一、首先需要在项目中引入better-scroll 1. 在package.json 直接写入 "better-scroll":"^1.15.1" 版本以
    2020-06-30
  • Vue如何提升首屏加载速度实例解析

    Vue如何提升首屏加载速度实例解析

    在Vue项目中,引入到工程中的所有js、css文件,编译时都会被打包进vendor.js,浏览器在加载该文件之后才能开始显示首屏。若是引入的库众多,那么vendor.js文件体积将会相当的大,影响
    2020-06-25