Vue3?通過(guò)作用域插槽實(shí)現(xiàn)樹(shù)形菜單嵌套組件
一、需求來(lái)源
工作中需要一種樹(shù)形菜單組件,經(jīng)過(guò)兩天的構(gòu)思最終通過(guò)作用域插槽實(shí)現(xiàn): 此組件將每個(gè)節(jié)點(diǎn)(插槽名為 node)暴露出來(lái)。
通過(guò)插槽的 attributes 向當(dāng)前插槽節(jié)點(diǎn)傳遞子項(xiàng) item(數(shù)據(jù)對(duì)象)和level(層深)參數(shù),在保持組件內(nèi)部極簡(jiǎn)的同時(shí)支持在數(shù)據(jù)模型中擴(kuò)展性。基本達(dá)到比較好的封裝顆粒度,大家可以在此基礎(chǔ)上無(wú)限擴(kuò)展封裝具體的業(yè)務(wù)邏輯。
二、效果圖
let list = reactive( [{ name:'1 一級(jí)菜單', isExpand: true,//是否展開(kāi)子項(xiàng) enabled: false,//是否可以響應(yīng)事件 child:[ { name:'1.1 二級(jí)菜單', isExpand: true, child:[ { name:'1.1.1 三級(jí)菜單', isExpand: true, }, ] }, { name:'1.2 二級(jí)菜單', isExpand: true, }, ] }, { name:'1.1 一級(jí)菜單', isExpand: true, child:[ { name:'1.1.1 二級(jí)菜單', isExpand: true, }, { name:'1.1.2 二級(jí)菜單', isExpand: false, child:[ { name:'1.1.2.1 三級(jí)菜單', 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 一級(jí)菜單', isExpand: true,//是否展開(kāi)子項(xiàng) enabled: false,//是否可以響應(yīng)事件 child:[ { name:'1.1 二級(jí)菜單', isExpand: true, child:[ { name:'1.1.1 三級(jí)菜單', isExpand: true, }, ] }, { name:'1.2 二級(jí)菜單', isExpand: true, }, ] }, { name:'1.1 一級(jí)菜單', isExpand: true, child:[ { name:'1.1.1 二級(jí)菜單', isExpand: true, }, { name:'1.1.2 二級(jí)菜單', isExpand: false, child:[ { name:'1.1.2.1 三級(jí)菜單', 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}子項(xiàng))`; }; </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>
以上就是Vue3 通過(guò)作用域插槽實(shí)現(xiàn)樹(shù)形菜單/嵌套組件的詳細(xì)內(nèi)容,更多關(guān)于Vue3 樹(shù)形菜單嵌套組件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
npm?install安裝報(bào)錯(cuò)的幾種常見(jiàn)情況
當(dāng)你跑起一個(gè)項(xiàng)目的時(shí)候,第一步需要先安裝依賴npm install,下面這篇文章主要給大家介紹了關(guān)于npm?install安裝報(bào)錯(cuò)的幾種常見(jiàn)情況,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07vue 如何處理防止按鈕重復(fù)點(diǎn)擊問(wèn)題
這篇文章主要介紹了vue 如何處理防止按鈕重復(fù)點(diǎn)擊問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10vue中頁(yè)面跳轉(zhuǎn)攔截器的實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于vue中頁(yè)面跳轉(zhuǎn)攔截器的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-08-08Vue的route-view子頁(yè)面調(diào)用父頁(yè)面的函數(shù)詳解
這篇文章主要介紹了Vue的route-view子頁(yè)面調(diào)用父頁(yè)面的函數(shù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07Vue監(jiān)聽(tīng)器簡(jiǎn)單使用及注意事項(xiàng)說(shuō)明
這篇文章主要介紹了Vue監(jiān)聽(tīng)器簡(jiǎn)單使用及注意事項(xiàng)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08關(guān)于webpack-dev-server配置代理解決前端開(kāi)發(fā)中的跨域問(wèn)題
這篇文章主要介紹了關(guān)于webpack-dev-server配置代理解決前端開(kāi)發(fā)中的跨域問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08玩轉(zhuǎn)vue的slot內(nèi)容分發(fā)
這篇文章主要介紹了玩轉(zhuǎn)vue的slot內(nèi)容分發(fā),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-09-09