vue3 -layui项目-左侧导航菜单栏

1.创建目录结构

进入cmd,先cd到项目目录(项目vue3-project)

cd vue3-project
mkdir -p src\\views\\home\\components\\menubar

2.创建组件文件

3.编辑menu-item-content.vue

<template>
	<component :is="props.com" :id="id">
		<template #icon  v-if="item.icon" >
			<lay-icon :type="item.icon"></lay-icon>
		</template>
		
		<template #title>
			{{ item.title }}
		</template>
		<slot />
	</component>
</template>

<script setup lang="ts">
import { computed } from 'vue';

const props= defineProps({
	// 菜单内容
	content: null,
	com: null,
	id: "",
});

// 获取父级菜单数据
const item = computed(() => {
	return props.content;
});

</script>
<style scoped lang="scss">

</style>

 4.编辑menu-item.vue

<template>
	<template v-if="item.children && item.children.length>0">
		<MenuItemContent :content="item" com="lay-sub-menu" :id="item.path" >
			<o-menu v-for="data in item.children"  :content="data" />
		</MenuItemContent>
	</template>
	<template v-else>
		<MenuItemContent :content="item" com="lay-menu-item"  :id="item.path" />
	</template>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import MenuItemContent from './menu-item-content.vue';

defineOptions({
		name:"OMenu"
	}
);
const props= defineProps({
	// 菜单内容
	content: null,
});

// 获取父级菜单数据
const item = computed(() => {
	return props.content;
});

</script>
<style scoped lang="scss">


</style>

5. 编辑menubar.vue

<template>
	<lay-menu  
			  v-model:selected-key="selectedKey"
			  v-model:open-keys="openKeys"
			  :tree="true" :indent="true"
			  :collapse="collapse"  @changeSelectedKey="changeSelectedKey">
		<template v-for="menu in menus">
			<MenuItem :content="menu" />
		</template>
	</lay-menu>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useRouter, useRoute } from 'vue-router'
import { useMenuStore } from '@/stores/menu'
import MenuItem from './menu-item.vue';

const menuStore = useMenuStore()
const { menus,collapse } = storeToRefs(menuStore)

const route = useRoute();
const router = useRouter()

const selectedKey = ref(route.path)
const openKeys = ref<string[]>([])

const changePath=()=>{
	let len = route.matched.length;
	if(len>1){
		for(var i=len-2;i>0;i--){
			openKeys.value.push(route.matched[i].path);
		}
	}
}

changePath();

const changeSelectedKey=(val: string)=>{
	router.push(val);
}

</script>
<style scoped lang="scss">

.layui-nav{
	background-color:var(--o-sidebar-bg-color);
}

.layui-nav-tree {
	width: var(--o-sidebar-width);
}

:deep(.layui-nav-item>a *){
	color:var(--o-sidebar-text-color);
}


:deep(.layui-nav-child){
	background-color:var(--o-sidebar-bg-color);
}


:deep(.layui-nav-item>a){
	display:flex;
	
}

</style>

6.添加菜单数据类型定义

types/menu.d.ts

declare interface Meta{
	id: string;
	name: string;
	path: string;
	title: string;
}

declare interface MenuMeta extends Meta{
	icon?: string;
}

declare interface MenuJsonInfo  extends MenuMeta{
	parentId: number;
}

declare interface MenuInfo extends MenuMeta{
	children?: MenuInfo[];
}

// 菜单信息
declare interface MenuInfoState {
  activeName: string;
  menu: MenuInfo;
}

7.添加store

stroes/menu.ts

import {defineStore} from 'pinia';

/**
 * 
 * @methods 设置菜单信息
 */
export const useMenuStore = defineStore('menu',{
	persist: true,//数据持久化设置
  state: (): MenuInfoState => ({
	collapse: false,
	menu: {
		name: '',
		title: '',
		path: '/',
		children: []
	},
  }),
  
  getters:{
	menus(state){
		return state.menu.children;
	}
  },
  actions: {

    async gen(datas: MenuJsonInfo[]) {
	  const that = this;
      const map:Record<number, MenuInfo> = {};
	  datas.forEach((item: MenuJsonInfo) =>{
		map[item.id] = {title:item.title,name:item.name, path:item.path,icon:item.icon, children: [] };
	  });

	  const findParent = (item: MenuJsonInfo)=>{
		  if(item.pid == 0 ){
				that.menu.children?.push(map[item.id]);
		  }else {
			  const parent = map[item.pid];
			  if(parent){
				  parent.children?.push(map[item.id]);
			  }
		  }
	  };
	  
	  datas.forEach((item: MenuJsonInfo) =>{
		  findParent(item);
	  });

    },
	handleCollape(){
		this.collapse = !this.collapse;
		return this.collapse;
	},
	clear(){
		this.menu.children =[];
	},

  },

  

});

展示菜单效果:

  • 11
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Oscar_0208

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值