vue3:菜单、标签页和面包屑联动效果

文章目录

    • 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 = "";
    }
  });
}

如有写的不明确的地方可以提出来,或者大佬们有更好的方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/536917.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

铭飞SQL注入严重信息泄露【附POC】

感谢您抽出 阅读本文 MCMS是一个<完整开源的Java CMS&#xff01;基于SpringBoot 2架构&#xff0c;前端基于vue、element ui。MCMS存在SQL注入漏洞&#xff0c;攻击者可通过该漏洞获取数据库敏感信息等。目前厂商暂未发布修复措施解决此安全问题&#xff0c;建议使用此软件…

配置QtCreator能加载自定义插件的环境

配置对应环境 引言查看当前版本配置能够加载插件的环境 引言 生成的自定义插件能在QtCreator的设计器中加载&#xff0c;需要满足当前使用的QtCreator的编译时所需的Qt库和编译器。 查看当前版本 这里需要先查看自己使用的QtCreator的版本&#xff0c;即生成QtCreator时使用…

【LeetCode】回溯算法类题目详解

所有题目均来自于LeetCode&#xff0c;刷题代码使用的Python3版本 回溯算法 回溯算法是一种搜索的方法&#xff0c;在二叉树总结当中&#xff0c;经常使用到递归去解决相关的问题&#xff0c;在二叉树的所有路径问题中&#xff0c;我们就使用到了回溯算法来找到所有的路径。 …

淘宝1688京东店铺所有商品数据接口(item_search_shop接口系列,可测试)

淘宝、1688和京东都提供了API接口供开发者调用&#xff0c;以获取店铺和商品的详细数据。对于您提到的item_search_shop接口系列&#xff0c;这主要是用于获取店铺所有商品的数据。然而&#xff0c;具体的接口名称和功能可能会因平台而异&#xff0c;且可能随着平台的更新而有所…

LigaAI x 极狐GitLab,共探 AI 时代研发提效新范式

近日&#xff0c;LigaAI 和极狐GitLab 宣布合作&#xff0c;双方将一起探索 AI 时代的研发效能新范式&#xff0c;提供 AI 赋能的一站式研发效能解决方案&#xff0c;让 AI 成为中国程序员和企业发展的新质生产力。 软件研发是一个涉及人员多、流程多、系统多的复杂工程&#…

微服务面试题二

1.什么是雪崩 微服务之间相互调用&#xff0c;因为调用链中的一个服务故障&#xff0c;引起整个链路都无法访问的情况。 如何解决雪崩&#xff1f; 超时处理&#xff1a;请求超时就返回错误信息&#xff0c;不会无休止等待仓壁模式&#xff1a;限定每个业务能使用的线程数&a…

cordova后台插件开发新手教程

typora-root-url: imags cordova后台插件开发新手教程 预安装环境&#xff1a;JDK11、Android studios、nodo.js 一、环境搭建 1.安装Cordova npm install -g cordova2.创建项目 cordova create 具体命令&#xff1a; cordova create 目录名 包名 项目名 执行结果终端&am…

大模型RAG(三)检索环节(Retriever)

1. 搜索索引 &#xff08;1&#xff09;向量存储索引 最原始的实现是使用平面索引 — 查询向量和所有块向量之间的暴力计算距离。根据索引选择、数据和搜索需求&#xff0c;还可以存储元数据&#xff0c;并使用元数据过滤器来按照日期或来源等条件进行信息检索。LlamaIndex 支…

【实战JVM】打破双亲委派机制之线程上下文类加载器

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

CS与MSF联动/shell互相反弹

Cs的shell反弹到msf 参考资料:https://blog.csdn.net/Zlirving_/article/details/113862910 先建立监听器 先建立一个监听器&#xff0c;和msf的要一一对应&#xff0c;上面的ip必须是可以ping通的大部分情况是外网ip Msf&#xff1a; use exploit/multi/handler set paylo…

Netty学习——实战篇1 BIO、NIO入门demo 备注

1 BIO 实战代码 Slf4j public class BIOServer {public static void main(String[] args) throws IOException {//1 创建线程池ExecutorService threadPool Executors.newCachedThreadPool();//2 创建ServerSocketServerSocket serverSocket new ServerSocket(8000);log.in…

高清无水印短视频素材去哪找?今天讲五个素材网站,记得收藏

在视频剪辑的世界里&#xff0c;我就像是那个经常带着一副老花镜在宝藏地图上寻宝的老海盗。每次寻宝之旅&#xff0c;我都能从九才素材网这个家门口的宝藏开始&#xff0c;然后驾驶我的老旧剪辑船&#xff0c;航向国际的深蓝大海&#xff0c;寻找那些只属于知情者的秘密宝藏。…

【C++进阶】C++异常详解

C异常 一&#xff0c;传统处理错误方式二&#xff0c;C处理的方式三&#xff0c;异常的概念四&#xff0c;异常的使用4.1 异常和捕获的匹配原则4.2 函数调用链中异常栈展开匹配原则4.3 异常的重新抛出&#xff08;异常安全问题&#xff09;4.4 RAII思想在异常中的作用 五&#…

使用Java+Maven+TestNG进行自动化测试

写作背景&#xff1a;有点Java基础的功能测试人员&#xff08;点点点工程师&#xff09;&#xff0c;所在项目有"去QE"的趋势&#xff0c;所以自己要多点亮其他技能&#xff0c;让路子走宽点。 简单说一下去QE&#xff1a;项目测试不再有专职的测试工程师来做&#x…

计算机网络——40各个层次的安全性

各个层次的安全性 安全电子邮件 Alice需要发送机密的报文m给Bob Alice 产生随机的对称秘钥&#xff0c; K s K_s Ks​使用 K s K_s Ks​对报文进行加密&#xff08;为了效率&#xff09;对 K s K_s Ks​使用Bob的公钥进行加密发送 K s ( m ) K_s(m) Ks​(m)和 K B ( K S ) K…

小程序/app/H5多端圈子社区论坛系统交友/社交/陌生人社交即时聊天私域话题社区论坛 行业圈子小程序 微信社区小程序圈子论坛社区小程序

项目介绍 这是一个社区论坛类小程序项目源码&#xff0c;可以实现用户发送自定义图文内容&#xff0c;点赞&#xff0c;评论&#xff0c;回复&#xff0c;记录评论过的帖子&#xff0c;记录发表过的帖子&#xff0c;左滑删除&#xff0c;在线实时接收消息&#xff0c;离线接收…

MySQL高级篇(索引概述、优缺点、结构 B+Tree)

目录 1、索引概述 2、索引优缺点 3、索引的结构 1、索引概述 介绍&#xff1a;索引&#xff08;index&#xff09;是帮助MySQL 高效获取数据 的 数据结构&#xff08;有序&#xff09;。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数…

分布式系统:缓存与数据库一致性问题

前言 缓存设计是应用系统设计中重要的一环&#xff0c;是通过空间换取时间的一种策略&#xff0c;达到高性能访问数据的目的&#xff1b;但是缓存的数据并不是时刻存在内存中&#xff0c;当数据发生变化时&#xff0c;如何与数据库中的数据保持一致&#xff0c;以满足业务系统…

java实现TCP交互

服务器端 import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.PriorityQueue; import java.util.Scanner;public class TCP_Serv…

(文章复现)考虑网络动态重构的分布式电源选址定容优化方法

参考文献&#xff1a; [1]朱俊澎,顾伟,张韩旦,等.考虑网络动态重构的分布式电源选址定容优化方法[J].电力系统自动化,2018,42(05):111-119. 1.摘要 以投资周期经济收益最高为目标&#xff0c;基于二阶锥规划提出了一种考虑网络动态重构的分布式电源选址定容优化方法。首先&am…