文章目录
-
- 1.整体思路
- 2.实现过程
概要
提示:这里可以添加技术概要
例如:
openAI 的 GPT 大模型的发展历程。
1.整体思路
在之前做的后台项目中,菜单、标签页和面包屑之间的联动,自己都是通过在路由前置守卫中,定义bus总线程通过.emit 和 .on 发送拿取需要的数据,然后再做一些自己想要的处理,实现自己想要的结果,后面在修改项目的时候就想要一中比较方便的办法,抛弃了通过bus总线程实现的方法。选择通过状态管理stroe来存储当前的路由信息控制三者的联动效果。
2.实现过程
1.创建你的组件文件,nav:菜单 、header:面包屑 、tabs:标签页,然后先把自己的基础页面信息。
2.将这些组件引入到view->index文件中
页面整体效果
2.创建store文件: index.ts 、user.ts 文件名字自己随便取,后面需要引入的时候不要把名称写错了
store //我习惯了命名 store ,实际可以取名 pinia 因为用到的组件库就是这个
* index
* user
index.ts
import {createPinia} from 'pinia'
let pinia= createPinia()
export default pinia
user.ts
import {defineStore} from 'pinia'
const useCounterStore = defineStore('appStore',{
state :()=> ({
menuiIsCollapse : false , //menu导航栏是否为展开
NavList: [], //menu导航栏的数据
TabsList:[], //标签页的显示数据
NowRouterPath :'' //当前路由
}),
actions : {
//菜单栏的缩放
updataMenuWidth(status:boolean){
this.menuiIsCollapse = status
this.menuiIsCollapse ? document.documentElement.style.setProperty('--el-aside-width', '64px') : document.documentElement.style.setProperty('--el-aside-width', '220px')
},
//第一次进入网站获取nav导航栏信息
oneSetMenuList (obj:any | []){
this.NavList = obj
},
//获取当前的路由信息
getNowRouterPath(path:object){
this.NowRouterPath = path.fullPath
this.screenTabsList(path)
},
//筛选tabs的数据显示 不存在就添加到 TabsList 中
screenTabsList(to_data:object){
if(this.TabsList.length == 0){
this.TabsList.push(to_data)
}else{
if(!this.TabsList.some(item => item.fullPath == to_data.fullPath)){
this.TabsList.push(to_data)
}
}
}
},
})
export default useCounterStore
3.创建router.ts文件,在src目录下新建router文件夹 - > 新建index.ts文件
import { createRouter ,createWebHashHistory , createWebHistory } from "vue-router";
import pinia from '@/store'
import useUserStore from "@/store/user";
import { inject } from "vue";
//必须 否则下面使用 _store 会报错
useUserStore(pinia)
const routes = [你自己的菜单数据]
const router = createRouter({
history : createWebHashHistory(),
routes
})
//前置路由守卫
router.beforeEach((to, from, next) => {
//调用 store 在mian.ts中定义
const _store = inject('store')
//将当前路由信息传递给store->user.ts中的方法
_store.getNowRouterPath(to)
const isAuthenticated = checkIfUserIsAuthenticated();
if (to.matched.some(record => record.meta.requiresAuth) && !isAuthenticated) {
next({ name: 'login' });
} else if (to.name === 'login' && isAuthenticated) {
next({ name: 'index' });
} else {
next();
}
});
function checkIfUserIsAuthenticated() {
// 检查本地存储中的认证状态
const isAuthenticated = localStorage.getItem('isAuthenticated');
// 如果认证状态为true,则返回true;否则返回false
return isAuthenticated === 'true';
}
export default router
没有注册userUserStore出现的错误,大概意思就是当前没有组件生产,拿取不到Mian.ts中注册的pinia:
附上mian.ts文件
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from "./router";
import ElementPlus from 'element-plus'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import 'element-plus/dist/index.css'
import './assets/css/global.less';
import { createPinia } from "pinia";
import bus from "./mitt";
import useCounterStore from "@/store/user";
import { storeToRefs } from 'pinia';
const pinia = createPinia();
const store = useCounterStore()
const storerefs = storeToRefs(store)
//模拟数据
import { mockXHR } from "./mock/index";
mockXHR()
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(pinia)
app.use(router)
app.use(ElementPlus)
//VUE提供了provide 和 inject来解决了这个问题。无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者。
app.provide('store_state', storerefs) //拿取到的pinia的state
app.provide('store', store) //拿到的整个pinia
app.provide('bus', bus)
app.mount('#app')
4.菜单文件 nva->index.vue
<script lang="ts" setup>
import { onMounted, reactive, ref ,watch,inject} from "vue";
import { useRoute } from "vue-router";
import { get } from "../../axios/api";
import bus from "@/mitt";
const isCollapse = ref(true);
const router = useRoute();
let nowRouter = ref("");
let NavList = ref([]);
let childPath = ref([]);
const store = inject('store')
const store_state = inject('store_state')
//监听当前路由信息的变化 newVlaue是新值 ,vlaue 是变化之前的旧值
watch(()=>store_state.NowRouterPath.value,(newValue,value)=>{
//判断当前的菜单数据信息中,是否包含新的路由数据,nowRouter赋值为新的路由,nav就会选中高亮显示
NavList.value.map((item) => {
newValue.indexOf(item.fullPath) == -1
? item.children.map((child: any) => {
nowRouter.value = newValue;
router.fullPath.indexOf(newValue) !== -1 ? (nowRouter.value = newValue) : "";
})
: "";
});
})
onMounted(() => {
//这个只是判断请求的nav数据是否存在本地中,存在就不请求接口了
if(sessionStorage.getItem('NavList')){
NavList.value = JSON.parse(sessionStorage.getItem('NavList'))
getNowPath()
}else{
getNavList()
}
});
//函数
const getNavList = ()=>{
let params = {
token: localStorage.getItem("token"),
};
get("/api/getMenuList", params).then((res) => {
NavList.value = res.data;
store.oneSetMenuList(NavList);
sessionStorage.setItem('NavList',JSON.stringify(NavList.value))
getNowPath()
});
}
const ClickToGo = (data)=>{
}
const getNowPath = () =>{
NavList.value.map((item) => {
item.children.length !== 0
? item.children.map((child: any) => {
childPath.value.push(child.path);
})
: childPath.value.push(item.path);
});
childPath.value.map((item) => {
if (router.path.indexOf(item) !== -1) {
nowRouter.value = item;
}
});
}
</script>
<template>
<el-menu
class="el-menu-vertical-demo"
:collapse="store_state.menuiIsCollapse.value"
:unique-opened="true"
:router="true" //为true的话,可以根据点击菜单中绑定的index是'/index'定义的路由,可点击直接跳转
:default-active="nowRouter"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
>
<template v-for="(item, index) in NavList">
<el-sub-menu v-if="item.children.length !== 0" :index="item.id">
<template #title> //下拉菜单
<el-icon><component :is="item.web_icon" /></el-icon>
<span>{{ item.title }}</span>
</template> //点击跳转菜单
<el-menu-item-group v-for="(children, k) in item.children">
<el-menu-item :index="children.path" @click="ClickToGo(children)">
{{ children.title }}</el-menu-item
>
</el-menu-item-group>
</el-sub-menu>
<el-menu-item v-else :index="item.path">
<el-icon><component :is="item.web_icon" /></el-icon>
<template #title>{{ item.title }}</template>
</el-menu-item>
</template>
</el-menu>
</template>
<style scoped lang="less">
</style>
5.tab组件
<template>
<div class="container" >
<el-tabs
v-model="editableTabsValue"
type="card"
closable
@tab-remove="removeTab"
@tab-click="getRouter"
>
<el-tab-pane
v-for="(item, index) in editableTabs"
:key="index"
:label="item.meta.name"
:name="item.fullPath"
>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script lang="ts" setup>
import { defineComponent, ref, onMounted ,inject,watch} from "vue";
import bus from "@/mitt";
import { useRouter } from "vue-router";
const store = inject('store')
const store_state = inject('store_state')
//直接赋值为当前的路由 editableTabsValue 对应到 el-tab-pane中的:name 如果相同就会自动高亮显示
let editableTabsValue = store_state.NowRouterPath;
//pinia中保存的 tabs数据
const editableTabs = store_state.TabsList
// 页面加载时执行
onMounted(() => {});
// 移除选项卡
const removeTab = (targetName: string) => {};
// 点击选项卡
const getRouter = (i: any) => {};
</script>
6.header 面包屑组件
<template>
<div class="header-box">
<div class="header_item">
<el-breadcrumb separator="/" class="header_left_title">
<el-breadcrumb-item :to="{ path: '/home' }">主页</el-breadcrumb-item>
<el-breadcrumb-item>{{ titleList.Pname }}</el-breadcrumb-item>
<el-breadcrumb-item v-if="titleList.name">{{
titleList.name
}}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, defineProps, provide, inject ,watchEffect ,watch} from "vue";
import { useRouter, useRoute } from "vue-router";
import { ref, reactive } from "vue";
const router = useRoute();
//面包屑显示数据
let titleList = reactive({ Pname: "", name: "" });
const store = inject('store')
const store_state = inject('store_state')
onMounted(() => {
//拿取router 路由信息
getMenuList(router.path);
});
//监听当前路由的信息变化
watch(()=>store_state.NowRouterPath.value,(newValue,value)=>{
getMenuList(newValue);
})
function getMenuList(path) {
//path:当前路由 ; 拿到nav菜单数据,对比是否能找到path对应的菜单信息,
let menuList = JSON.parse(sessionStorage.getItem('NavList'))
menuList.map((item) => {
if (item.path !== path) {
//判断是否存在children 可点击菜单
item.children.length !== 0
? item.children.map((child) => {
//存入 下拉菜单的名称 和 筛选出的点击菜单名称
if (child.path == path) {
titleList.Pname = item.title;
titleList.name = child.title;
}
})
: "";
} else {
titleList.Pname = item.title;
titleList.name = "";
}
});
}
如有写的不明确的地方可以提出来,或者大佬们有更好的方法。