Vue3 通過作用域插槽實現樹形菜單嵌套組件
一、需求來源
工作中需要一種樹形菜單組件,經過兩天的構思最終通過作用域插槽實現: 此組件將每個節點(插槽名為 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 樹形菜單嵌套組件的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- Vue3中插槽(slot)的全部使用方法
- Vue3常用的通訊方式總結與實例代碼
- JavaScript–在Vue中使用插槽:slot
- Vue3.2單文件組件setup的語法糖與新特性總結
- vue3中ref綁定dom或者組件失敗的原因及分析