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

   2023-02-08 学习力0
核心提示:目录一、需求来源二、效果图三、使用示例(VTreeNodeDemo.vue)四、源码(VTreeNode.vue):一、需求来源工作中需要一种树形菜单组件,经过两天的构思最终通过作用域插槽实现: 此组件将每个节点(插槽名为 node)暴露出来。通过插槽的 attributes 向当前插槽

一、需求来源

工作中需要一种树形菜单组件,经过两天的构思最终通过作用域插槽实现: 此组件将每个节点(插槽名为 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, },
        ]},
    ]
  },]
);

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

三、使用示例(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 树形菜单嵌套组件的资料请关注其它相关文章!

原文地址:https://juejin.cn/post/7165359183582199815
 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • vue3+TS 自定义指令:长按触发绑定的函数
    vue3+TS 自定义指令:长按触发绑定的函数而然间看到一个在vue2中写的长按触发事件的自定义指定,想着能不能把他copy到我的vue3项目中呢。编写自定义指令时遇到的几个难点1.自定义指令的类型在ts中写任何东西都要考虑到类型的问题,自定义指令的类型问题依然存
    03-08
  • Vue3 企业级优雅实战 - 组件库框架 - 9 实现组
    上文搭建了组件库 cli 的基础架子,实现了创建组件时的用户交互,但遗留了 cli/src/command/create-component.ts 中的 createNewComponent 函数,该函数要实现的功能就是上文开篇提到的 —— 创建一个组件的完整步骤。本文咱们就依次实现那些步骤。(友情提示
    03-08
  • vue3和百度地图关键字检索 定位 点击定位
    vue3和百度地图关键字检索 定位 点击定位
    效果图在index.html中引入百度地图开放平台  去申请你的ak 非常的简单可以自己百度 一下!-- 这个用官网给的有好多警告 更具百度的把 https://api.map.baidu.com/getscript?v=2.0ak=xxxxxxxxxxxxxxxxxxxxx 换为这个就没有那么多 报错了 --scripttype="text/j
    03-08
  • Vue3+TypeScript 项目中,配置 ESLint 和 Prett
    接上篇:从0搭建vite-vue3-ts项目框架:配置less+svg+pinia+vant+axios文档同步项目gitee:https://gitee.com/lixin_ajax/vue3-vite-ts-pinia-vant-less.git 一、Eslint:用于检测代码安装eslint相关依赖yarn add eslint eslint-plugin-vue @typescript-esli
    03-08
  • 一文带你了解Vue3中toRef和toRefs的用法 vue $refs的用法
    一文带你了解Vue3中toRef和toRefs的用法 vue $r
    toRef 顾名思义,不是ref 响应式数据,给它转成ref 响应式数据通俗易懂的理解: templateh3姓名:{{ person.name }}/h3h3年龄:{{ person.age }}/h3h3薪资:{{ person.job.j1.salary }}/h3button @click="person.name += '!'"修改姓名/buttonbutton @click="
    03-08
  • vue3.0 vue-router4.0打包后页面空白的解决方法
    vue3.0 vue-router4.0打包后页面空白的解决方
    开发环境可以正常渲染页面,路由跳转都没有问题,但是打包之后本地打开index.html出现报错或者页面空白的情况:脚手架版本:vue-router版本:第一种报错-资源加载失败这种错误是因为vue.config.js的配置里面 publicPath写了绝对路径,生产环境改为./相对路径
    03-08
  • vue3日历控件的具体实现 vue日历组件如何显示节日
    vue3日历控件的具体实现 vue日历组件如何显示节
    很多地方都要用到日历控件,比如生日、出发到达日期等等,本文就来介绍一下vue3日历控件的具体实现,具体如下效果如下:templatediv class="cal_con" style="margin-left:200px"div class="cal_header"!-- 顶部左侧 --div class="cal_header_left"div class="
    03-08
  • vue3全局组件自动注册功能实现 vue 全局注册
    vue3全局组件自动注册功能实现 vue 全局注册
    目录vue3全局组件自动注册前言:补充: Vue3注册全局组件1.注册单个全局组件2.批量注册全局组件vue3全局组件自动注册前言:本文主要讲述vue3的全局公共组件的自动注册第一步:建文件需要在src/components 下创建一个文件夹用于存放封装的公共组件(这里我起
    03-08
  • vue3项目目录结构示例详解 vue3.0目录结构
    目录一、vue3项目的目录结构详解二、部分主要文件详解1、index.html2、main.js(main.ts)3. package.json三、其他说明1. node版本错误2. 如何调用全局属性3. vue文件中应用vue3.0的api总结一、vue3项目的目录结构详解node_modules:通过 npm install 下载安
    03-08
  • vue3之Suspense加载异步数据的使用
    vue3之Suspense加载异步数据的使用
    Suspense使用templateSuspensetemplate #defaultProductList/ProductList/templatetemplate #fallback divloading.../div /template/Suspense/templatescript setup lang="ts" name="Cart"import ProductList from "./ProductList.vue";/scripts
    03-08
点击排行