欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue3.0實(shí)現(xiàn)無(wú)限級(jí)菜單

 更新時(shí)間:2022年07月15日 10:29:28   作者:懶人Ethan  
這篇文章主要為大家詳細(xì)介紹了基于Vue3.0實(shí)現(xiàn)無(wú)限級(jí)菜單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

業(yè)務(wù)需求

菜單項(xiàng)是業(yè)務(wù)系統(tǒng)的重要組成部分,一般業(yè)務(wù)系統(tǒng)都要支持顯示多級(jí)業(yè)務(wù)菜單,但是根據(jù)每個(gè)業(yè)務(wù)人員的權(quán)責(zé)不同,看到的的菜單項(xiàng)也是不同的。

這就要求頁(yè)面可以支持無(wú)限極菜單顯示,根據(jù)每個(gè)用戶的權(quán)限不同,后臺(tái)服務(wù)返回對(duì)應(yīng)的菜單項(xiàng)。

本文基于Vue 3.0實(shí)現(xiàn)了一個(gè)可配置的無(wú)限等級(jí)菜單,關(guān)鍵代碼如下:

后端返回的菜單項(xiàng)數(shù)據(jù)結(jié)構(gòu)

后端服務(wù)一般不會(huì)直接返回一個(gè)樹型結(jié)構(gòu)菜單集合給前端,這樣做也不合理。前端應(yīng)該根據(jù)自己的具體需求,構(gòu)建自己的菜型單樹。后端返回的數(shù)據(jù)結(jié)構(gòu)一般包含以下一個(gè)字段:

  • Id 菜單ID, 數(shù)字類型
  • pId當(dāng)前菜單的父級(jí)菜單ID, 數(shù)字類型
  • title 菜單的標(biāo)題
  • link 菜單對(duì)應(yīng)的鏈接
  • order 同級(jí)菜單的排列順序,數(shù)字類型

其他業(yè)務(wù)字段需要具體問題具體分析,在這里不再贅述。本文不再討論后端如何進(jìn)行菜單項(xiàng)的權(quán)限控制,所使用的菜單內(nèi)容,包括在一個(gè)JSON文件中,具體見附錄。

菜單內(nèi)容是一個(gè)足球數(shù)據(jù)管理系統(tǒng),包括多級(jí)菜單:

  • 第一級(jí)菜單只有一項(xiàng),是所有節(jié)點(diǎn)的祖先節(jié)點(diǎn)。
  • 第二級(jí)菜單包括聯(lián)賽管理,俱樂部管理和球員管理
  • 第三級(jí)菜單包括二級(jí)菜單內(nèi)容的CRUD。

關(guān)鍵代碼

為了支持無(wú)限級(jí)菜單,本文所有關(guān)鍵算法全部基于遞歸實(shí)現(xiàn)。主要包括:

1.后端數(shù)據(jù)轉(zhuǎn)換為樹形結(jié)構(gòu)
2.后端數(shù)據(jù)排序
3.基于菜單樹形結(jié)構(gòu)生成Vue的路由數(shù)據(jù)
4.菜單組件的遞歸調(diào)用

后端數(shù)據(jù)轉(zhuǎn)為樹形結(jié)構(gòu)

dataToTree函數(shù)調(diào)用的實(shí)參是附錄的JSON數(shù)據(jù),該代碼參考Vue 3.0的AST樹轉(zhuǎn)換的代碼,具體思想是:

1.將集合的數(shù)據(jù)分為父節(jié)點(diǎn)和子節(jié)集合,最外層的父節(jié)點(diǎn)為pId為0的節(jié)點(diǎn)。
2.在子節(jié)點(diǎn)中找到當(dāng)前父節(jié)點(diǎn)的直接子節(jié)點(diǎn),將其從當(dāng)前子節(jié)點(diǎn)集合剔除。
3.遞歸回到1,尋找子節(jié)點(diǎn)的子節(jié)點(diǎn)。
4.如果當(dāng)前子節(jié)點(diǎn)不是任何節(jié)點(diǎn)的父節(jié)點(diǎn),將該子節(jié)點(diǎn)放入父節(jié)點(diǎn)的children集合中。

在生成當(dāng)前樹型結(jié)構(gòu)菜單數(shù)據(jù)后,可以將該數(shù)據(jù)保存在vuex中,作為公共數(shù)據(jù)便于其他模塊使用。

function dataToTree(data) {
? const parents = data.filter((item) => item.pId === 0);
? const children = data.filter((item) => item.pId !== 0);
? toTree(parents, children);
? return parents;
? function toTree(parents, children) {
? ? for (var i = 0; i < parents.length; ++i) {
? ? ? for (var j = 0; j < children.length; ++j) {
? ? ? ? if (children[j].pId === parents[i].Id) {
? ? ? ? ? let _children = deepClone(children, []);
? ? ? ? ? toTree([children[j]], _children);
? ? ? ? ? if (parents[i].children) {
? ? ? ? ? ? parents[i].children.push(children[j]);
? ? ? ? ? } else {
? ? ? ? ? ? parents[i].children = [children[j]];
? ? ? ? ? }
? ? ? ? }
? ? ? }
? ? }
? }
}

function deepClone(source, target) {
? var _tar = target || {};
? let keys = Reflect.ownKeys(source);
? keys.map((key) => {
? ? if (typeof source[key] === "object") {
? ? ? _tar[key] =
? ? ? ? Object.prototype.toString.call(source[key]) === "[object Array]"
? ? ? ? ? ? []
? ? ? ? ? : {};
? ? ? deepClone(source[key], _tar[key]);
? ? } else {
? ? ? _tar[key] = source[key];
? ? }
? });
? return _tar;
}

菜單項(xiàng)排序

根據(jù)同級(jí)節(jié)點(diǎn)的order值進(jìn)行排序,本文沒有將該排序和上節(jié)的樹型結(jié)構(gòu)轉(zhuǎn)換放在一起,主要是考慮有些系統(tǒng)可能不需要排序。如果需要,每次添加元素都要進(jìn)行一次排序,效率低下,所以在獲取樹型結(jié)構(gòu)后,再進(jìn)行一次排序,具體排序函數(shù)如下:

function SortTree(tree) {
? tree = tree.sort((a, b) => a.order - b.order);
? tree.map((t) => {
? ? if (t.children) {
? ? ? t.children = SortTree(t.children);
? ? }
? });

? return tree;

采用最簡(jiǎn)單的遞歸方式,遍歷當(dāng)前樹型集合,按照order字段的升序方式進(jìn)行排序,如果當(dāng)前節(jié)點(diǎn)有children項(xiàng),遞歸排序。

基于菜單樹形結(jié)構(gòu)生成Vue的路由數(shù)據(jù)

在獲取樹型菜單后后,我們可以基于當(dāng)前數(shù)據(jù),生成該用戶在App中要使用到的路由項(xiàng),具體代碼如下:

function TreeToRoutes(treeData, routes) {
? routes = routes || [];
? for (var i = 0; i < treeData.length; ++i) {
? ? routes[i] = {
? ? ? path: treeData[i].link,
? ? ? name: treeData[i].name,
? ? ? component: () => import(`@/views/${treeData[i].name}`),
? ? };
? ? if (treeData[i].children) {
? ? ? routes[i].children = TreeToRoutes(
? ? ? ? treeData[i].children,
? ? ? ? routes[i].children
? ? ? );
? ? }
? }
? return routes;
}

1.遍歷樹型菜單,將當(dāng)前菜單項(xiàng)的link和tname復(fù)制到Vue路由數(shù)據(jù)的path和name上,component采用動(dòng)態(tài)加載方式。
2.如果當(dāng)前菜單項(xiàng)包含子節(jié)點(diǎn)children,遞歸調(diào)用,復(fù)制其子節(jié)點(diǎn)內(nèi)容。

在main.js方法中,將菜單數(shù)據(jù)通過(guò)vuex進(jìn)行讀取,然后調(diào)用上述算法生成路由數(shù)據(jù)。將該數(shù)據(jù)直接加載到Vue的路由中,保證了如果當(dāng)前用戶沒有某一個(gè)菜單的權(quán)限,即使通過(guò)URL進(jìn)行訪問,也是訪問不到的,因?yàn)锳pp只會(huì)為有權(quán)限的菜單項(xiàng)生成路由數(shù)據(jù)。如果用戶沒有某一個(gè)菜單的權(quán)限,也就不會(huì)從后端獲取到該菜單的數(shù)據(jù),也就不會(huì)為該菜單項(xiàng)生成路由。

菜單組件的遞歸調(diào)用

菜單組件代碼如下:

<template>
? <div>
? ? ? <ul v-if="data.children && data.children.length > 0">
? ? ? ? ? <li><router-link :to="data.link">{{data.title}}</router-link></li>?
? ? ? ? ? <menu-item :data="item" :key="index" ?v-for="(item,index) in data.children">
? ? ? </ul>
? ? ? <ul v-else>
? ? ? ? ? <li><router-link :to="data.link">{{data.title}}</router-link></li>?
? ? ? </ul>
? </div>
</template>

<script>
export default {
? ? name: "MenuItem",
? ? props:{
? ? ? ? data: Object
? ? }
}
</script>

如果當(dāng)前菜單項(xiàng)包含子節(jié)點(diǎn),則遞歸調(diào)用MenuItem組件自己

菜單組件調(diào)用的代碼如下:

<template>
? <div>
? ? ?<menu-item :data="item" :key="index" v-for="(item,index) in data" />
? </div>
</template>

<script>
import MenuItem from './MenuItem'
export default {
? ? name: "Page",
? ? components:{
? ? ? ? MenuItem
? ? }
}
</script>

由于生成的菜單數(shù)據(jù)結(jié)構(gòu)最外層是數(shù)據(jù),所以MenuItem組件需要進(jìn)行循環(huán)調(diào)用。

附錄-菜單項(xiàng)數(shù)據(jù)

export default [
? {
? ? Id: 15,
? ? pId: 0,
? ? name: "all",
? ? title: "all",
? ? link: "/all",
? ? order: 2,
? },
? {
? ? Id: 1,
? ? pId: 15,
? ? name: "clubs",
? ? title: "Club Management",
? ? link: "/clubs",
? ? order: 2,
? },
? {
? ? Id: 2,
? ? pId: 15,
? ? name: "leagues",
? ? title: "League Management",
? ? link: "/leagues",
? ? order: 1,
? },
? {
? ? Id: 3,
? ? pId: 15,
? ? name: "players",
? ? title: "Player Management",
? ? link: "/players",
? ? order: 3,
? },
? {
? ? Id: 5,
? ? pId: 2,
? ? name: "LeagueDelete",
? ? title: "Delete League",
? ? link: "/leagues/delete",
? ? order: 3,
? },
? {
? ? Id: 6,
? ? pId: 2,
? ? name: "LeagueUpdate",
? ? title: "Update League",
? ? link: "/leagues/update",
? ? order: 2,
? },
? {
? ? Id: 7,
? ? pId: 2,
? ? name: "LeagueAdd",
? ? title: "Add League",
? ? link: "/leagues/add",
? ? order: 1,
? },
? {
? ? Id: 8,
? ? pId: 3,
? ? name: "PlayerAdd",
? ? title: "Add Player",
? ? link: "/players",
? ? order: 1,
? },
? {
? ? Id: 9,
? ? pId: 3,
? ? name: "PlayerUpdate",
? ? title: "Update Player",
? ? link: "/players",
? ? order: 3,
? },
? {
? ? Id: 10,
? ? pId: 3,
? ? name: "PlayerDelete",
? ? title: "Delete Player",
? ? link: "/players",
? ? order: 2,
? },
? {
? ? Id: 11,
? ? pId: 1,
? ? name: "ClubAdd",
? ? title: "Add Club",
? ? link: "/clubs/add",
? ? order: 3,
? },
? {
? ? Id: 12,
? ? pId: 1,
? ? name: "ClubUpdate",
? ? title: "Update Club",
? ? link: "/clubs/update",
? ? order: 1,
? },
? {
? ? Id: 13,
? ? pId: 1,
? ? name: "ClubDelete",
? ? title: "Delete Club",
? ? link: "/clubs/delete",
? ? order: 2,
? },
];

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Vue3中reactive丟失響應(yīng)式的問題解決(避大坑!)

    Vue3中reactive丟失響應(yīng)式的問題解決(避大坑!)

    這篇文章主要給大家介紹了關(guān)于Vue3中reactive丟失響應(yīng)式的問題解決,vue3中reactive定義的引用類型直接賦值導(dǎo)致數(shù)據(jù)失去響應(yīng)式 ,需要的朋友可以參考下
    2023-07-07
  • vue-router 中 meta的用法詳解

    vue-router 中 meta的用法詳解

    今天小編就為大家分享一篇vue-router 中 meta的用法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • vue中刷新子組件重新加載子組件三種方法

    vue中刷新子組件重新加載子組件三種方法

    組件是Vue.js最強(qiáng)大的功能之一,組件可以擴(kuò)展HTML元素,封裝可重用的代碼,這篇文章主要給大家介紹了關(guān)于vue中刷新子組件重新加載子組件三種方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • Vue 2.0學(xué)習(xí)筆記之使用$refs訪問Vue中的DOM

    Vue 2.0學(xué)習(xí)筆記之使用$refs訪問Vue中的DOM

    這篇文章主要介紹了Vue 2.0學(xué)習(xí)筆記之使用$refs訪問Vue中的DOM,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • 解決vue+ element ui 表單驗(yàn)證有值但驗(yàn)證失敗問題

    解決vue+ element ui 表單驗(yàn)證有值但驗(yàn)證失敗問題

    這篇文章主要介紹了vue+ element ui 表單驗(yàn)證有值但驗(yàn)證失敗,本文通過(guò)實(shí)例代碼給大家分享解決方案,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-01-01
  • vue中關(guān)于redirect(重定向)初學(xué)者的坑

    vue中關(guān)于redirect(重定向)初學(xué)者的坑

    這篇文章主要介紹了vue中關(guān)于redirect(重定向)初學(xué)者的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Vue-loader使用教程

    Vue-loader使用教程

    Vue-loader其實(shí)就是一個(gè)webpack的loader,用來(lái)把vue組件轉(zhuǎn)換成可部署的js, html, css模塊,這篇文章主要介紹了Vue-loader使用教程,需要的朋友可以參考下
    2022-08-08
  • vue中使用極驗(yàn)驗(yàn)證碼的方法(附demo)

    vue中使用極驗(yàn)驗(yàn)證碼的方法(附demo)

    這篇文章主要介紹了vue中使用極驗(yàn)驗(yàn)證碼的方法(附demo)本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-12-12
  • vue 自定義icon圖標(biāo)的步驟

    vue 自定義icon圖標(biāo)的步驟

    這篇文章主要介紹了vue 自定義icon的圖標(biāo)的步驟,文中大概給大家分為兩步驟,通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-08-08
  • 淺析Proxy可以優(yōu)化vue的數(shù)據(jù)監(jiān)聽機(jī)制問題及實(shí)現(xiàn)思路

    淺析Proxy可以優(yōu)化vue的數(shù)據(jù)監(jiān)聽機(jī)制問題及實(shí)現(xiàn)思路

    這篇文章主要介紹了淺析Proxy可以優(yōu)化vue的數(shù)據(jù)監(jiān)聽機(jī)制問題及實(shí)現(xiàn)思路,需要的朋友可以參考下
    2018-11-11

最新評(píng)論