页面整体效果图
1.页面布局
首先布置好布局,页面的整体效果如下:
<template>
<div class="box">
<div class="box__left">
<!-- 侧边菜单栏标签 -->
<index-sidebar></index-sidebar>
<!-- 侧边菜单栏标签 -->
</div>
<div class="box__right">
<index-header></index-header>
<!-- tabs标签 -->
<index-tabs></index-tabs>
<!-- tabs标签 -->
</div>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
@import '@/assets/css/base.scss';
.box{
display: flex;
&__left{
width: 110px;
}
&__right{
flex: 1;
}
}
</style>
2.侧边栏用el-menu标签,标签的选中状态与属性default-active有关,tabs标签用el-tabs,选中转态态与editableTabsValue有关,实现关联就是将2个属性的值相同即可。由于页面是封装成了子组件,所以这里el-tabs的标签属性editableTabs,editableTabsValue在pinia中进行状态管理,在进行引入。
import { defineStore } from 'pinia'
import {ref} from 'vue'
export const tabsStore = defineStore('tabs',()=>{
const editableTabsValue =ref('home')
const editableTabs = ref([
{
title: '工作台',
name: 'home',
},
])
return {editableTabs,editableTabsValue}
})
3.在index-tabs.vue中,映入Pinia里的editableTabs,editableTabsValue,在removeTab事件中不希望移除第一个标签,先进行判断是否点击的是第一个即可,changTab事件点击跳转对应路由
<template>
<div class="tabs">
<el-tabs v-model="tab.editableTabsValue" type="card" class="demo-tabs" closable @tab-remove="removeTab" @tab-change="changeTab">
<el-tab-pane v-for="item in tab.editableTabs" :key="item.name" :label="item.title" :name="item.name">
<keep-alive><router-view ></router-view></keep-alive>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script lang="ts" setup>
import { ref} from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
import { tabsStore } from '@/stores/tabs.js'
const tab = tabsStore()
const removeTab = (targetName: string) => {
if (targetName !== 'home') {//判断点击是否为工作台
if (tab.editableTabsValue === targetName) {
tab.editableTabs.forEach((tabs, index) => {
if (tabs.name === targetName) {
const nextTab = tab.editableTabs[index + 1] || tab.editableTabs[index - 1]
if (nextTab) {
router.push(nextTab.name)
}
}
})
}
//过滤掉当前点击的tab标签
tab.editableTabs = tab.editableTabs.filter((tab) => tab.name !== targetName)
}
}
const changeTab = (targetName: string)=>{
router.push(targetName)
}
</script>
4.在index-sidebar.vue中,先设置好el-menu的router属性,对应的index填上跳转的路由。default-active这里命名为Eindex,在,通过watch监听事件监听路由的变化,先将tab.editableTabs中的title值取出为一个数组,再对当前route.name进行判断是否存在,不存在则添加到tab.editableTabs数组中。Eindex的值与当前路由名字保持一致即可实现tabs和menu的互联。
5.当刷新页面时,路由会只保留第一个tab标签,可能与当前路由对应不上,需要在onMounted中判断当前路由,若不等于第一个标签的路由,则tab.editableTabs数组添加该值,Eindex值也要跟当前路由保持一致。
<template>
<div class="sidebar">
<!-- logo -->
<div class="sidebar__logo">logo</div>
<!-- logo--end -->
<!-- 侧边导航 -->
<el-menu class="el-menu-vertical-demo" :default-active="Eindex" unique-opened router>
<el-sub-menu index="1">
<template #title>
<el-icon>
<location />
</el-icon>
<span>影片</span>
</template>
<el-menu-item-group title="影片">
<el-menu-item index="film-management" name="影片管理">影片管理</el-menu-item>
<el-menu-item index="film-types">影片分类</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>
<el-icon>
<location />
</el-icon>
<span>影院</span>
</template>
<el-menu-item-group title="影院">
<el-menu-item index="cinema-management">影院管理</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="3">
<template #title>
<el-icon>
<location />
</el-icon>
<span>用户</span>
</template>
<el-menu-item-group title="用户">
<el-menu-item index="user-management">用户管理</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</el-menu>
<!-- 侧边导航--end -->
</div>
</template>
<script setup lang="ts">
import {useRouter,useRoute} from 'vue-router'
const router = useRouter()
const route = useRoute()
import {watch,ref, onMounted} from 'vue'
import { tabsStore } from '@/stores/tabs.js'
const tab = tabsStore()
const Eindex = ref()
onMounted(()=>{
if(route.name!=='home'){
tab.editableTabs.push({
title: route.meta.title,
name: route.name,
})
tab.editableTabsValue = route.name
Eindex.value=route.name
}
})
watch(route,()=>{
const arr =[]
tab.editableTabs.forEach(item => {
arr.push(item.title)
});
const res = arr.indexOf(route.meta.title)
if(res==-1){
tab.editableTabs.push({
title: route.meta.title,
name: route.name,
})
}
tab.editableTabsValue = route.name
Eindex.value=route.name
})
</script>