Vue3 通过作用域插槽实现树形菜单嵌套组件
作者:SoaringHeart 时间:2024-05-28 15:42:28
一、需求来源
工作中需要一种树形菜单组件,经过两天的构思最终通过作用域插槽实现: 此组件将每个节点(插槽名为 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
来源:https://juejin.cn/post/7165359183582199815
标签:Vue3,树形菜单,嵌套组件,作用域,插槽
0
投稿
猜你喜欢
解决Pandas的DataFrame输出截断和省略的问题
2021-10-28 10:22:19
Python3.4学习笔记之类型判断,异常处理,终止程序操作小结
2022-06-03 10:45:54
Go gRPC服务客户端流式RPC教程
2023-07-16 06:08:55
五个有趣的Python整蛊小程序合集
2022-10-27 12:34:10
利用Python的装饰器解决Bottle框架中用户验证问题
2022-10-07 07:49:15
PHP 进程锁定问题分析研究
2023-11-21 18:14:10
如何用python写个模板引擎
2022-07-29 06:09:45
Python的Django中将文件上传至七牛云存储的代码分享
2023-11-28 14:00:24
PL/SQL 类型格式转换
2009-02-26 11:07:00
HTML邮件的又一点思考
2009-05-06 13:33:00
Python线性回归图文实例详解
2023-04-06 07:31:42
答题辅助python代码实现
2022-06-30 19:57:35
python基础之文件操作
2022-12-23 01:15:53
Python中BeautifulSoup通过查找Id获取元素信息
2022-12-22 22:08:59
真正高效的SQLSERVER分页查询(多种方案)
2024-01-28 15:50:25
浅谈常用Java数据库连接池(小结)
2024-01-18 06:50:25
pytorch中的weight-initilzation用法
2022-03-22 23:28:24
浅析Python中的多进程与多线程的使用
2021-07-27 11:12:20
Windows自动执行python脚本操作步骤
2023-04-22 15:32:42
Selenium元素的常用操作方法分析
2021-09-21 14:51:54