vue3 + TS + elementplus + pinia实现后台管理系统左侧菜单联动实现 tab根据路由切换联动内容

news2024/7/6 18:15:54

效果图:

 home.vue页面代码

<template>
  <el-container>
    <el-aside width="collapse ? 200px : 70px">
      <el-button color="#626aef" @click="collapseToggle()">
        <el-icon>
          <Expand v-if="collapse" />
          <Fold v-else />
        </el-icon>
      </el-button>
      <el-menu
          :collapse="collapse"
          :default-active="store.bbc"
          class="el-menu-vertical-demo"
          unique-opened
          active-text-color="#ffd04b"
          text-color="#fff"
          background-color="transparent"
          @select="store.vv"
         >
       <left :dataToSon="store.mm" />
      </el-menu>
    </el-aside>
    <el-container>
      <el-header height="80px">
        <h1 @click="fff">大可的管理系统 - v1.0</h1>
        <div>
          <img src="@/assets/111.jpg" alt="">
          <span></span>
          <el-button type="primary" @click="LogOut">退出登录</el-button>
        </div>
      </el-header>
      <el-main>
        <tab></tab>
      </el-main>
      <el-footer height="50px">
        <p>&copy; 版权所有: 大可</p>
      </el-footer>
    </el-container>
  </el-container>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { useRouter } from "vue-router";
import left from "../left.vue";
import  tab from '../tab.vue';
import { ElMessage, ElMessageBox} from "element-plus";
import { useAuthStore } from '@/store';
import preventBack from 'vue-prevent-browser-back';//组件内单独引入
const mixins = [preventBack];
const store = useAuthStore();
const collapse = ref<boolean>(false)
const router = useRouter();
const tiao = () => {
  console.log('路由')
  router.push('/son1')
}
const fff = () => {
  router.replace('/son2')
}
const collapseToggle = () => {
  collapse.value = !collapse.value
}
const ggvv  = ref([1,2,3])
const handleOpen = () => {
  console.log()
}
const gg = (e) => {
  console.log(e)
}
const handleClose = () => {
  console.log()
}
const LogOut = () => {
  ElMessageBox.confirm(
      '确定要退出登录?',
      'Warning',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }
  )
      .then(() => {
        router.replace('/login')
        ElMessage({
          type: 'success',
          message: '退出成功',
        })
      })
      .catch(() => {
        ElMessage({
          type: 'info',
          message: '您取消了退出',
        })
      })
}
</script>

<style scoped>
.el-header {
  background: url("@/assets/111.jpg");
  background-color: #f3d19e;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.el-header h1 {
  font-size: 26px;
  color: #fff;
  letter-spacing: 10px;
}
.el-header div {
  margin-right: 30px;
}
.el-header img {
  width: 40px;
  border-radius: 40px;
  vertical-align: middle;
  margin-right: 10px;
}
.el-header span {
  font-size: 18px;
  color: #fff;
  margin-right: 10px;
}
.el-header el-button {
  margin-left: 10px;
}

.el-aside {
  height: 100vh;
  background: url('@/assets/111.jpg');
  transition: width 0.3s;
  text-align: right;
}
.el-aside .el-button {
   margin: 20px 10px 20px 0;
 }
.el-aside .el-menu {
  border-right: none;
}
.el-footer {
  background-color: #EBEEF5;
  display: flex;
  align-items: center;
}
.el-footer p {
  font-size: 12px;
  color: #666;
}


</style>

left.vue页面代码

<script setup lang="ts">
import { ref, defineProps } from 'vue';
import { useAuthStore } from '@/store';
type HeaderProps = {
  dataToSon: number[];
};
// 2. type 声明的HeaderProps 用 defineProps注册
const zz = defineProps<HeaderProps>();
const hhkk = zz.dataToSon;
const list = ref<Array<object>>([]);
const store = useAuthStore();
const gg = () => {

}
</script>

<template>
    <template v-for="(item, index) in hhkk" :key="item.id">
      <!-- 非叶子节点 -->
      <el-sub-menu v-if="item.children" :index="item.id">
        <template #title>
          <el-icon>
            <Setting />
          </el-icon>
          <span v-text="item.name"></span>
        </template>
        <left :dataToSon="item.children"/>
      </el-sub-menu>
      <!-- 叶子节点(功能节点) -->
      <el-menu-item v-else :index="item.path">
        <el-icon>
          <Menu />
        </el-icon>
        <span v-text="item.name"></span>
      </el-menu-item>

    </template>
</template>

<style scoped lang="stylus">
</style>

tab.vue页面代码

<template>
  <el-tabs
      v-model="store.bbc"
      type="card"
      class="demo-tabs"
      closable
      @tab-remove="store.kk"
      @tab-click="jj"
  >
<!--    @tab-click="jj"-->
    <el-tab-pane
        v-for="item in ff"
        :key="item.id"
        :label="item.name"
        :name="item.path"
    >
      <router-view :name="item.path" v-slot="{Component}">
        <keep-alive>
          <component :is="Component"></component>
        </keep-alive>
      </router-view>
    </el-tab-pane>
  </el-tabs>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import {useAuthStore} from '@/store';
import {useRouter} from "vue-router";
const store = useAuthStore();
const router = useRouter();
onMounted(() => {
  // store.bbc = router.currentRoute._value.fullPath;
})

const fv = store.bbc;

const jj = (e) => {
  // router.replace(e.props.name)
  console.log(e)
}
const hh = (ee) => {
  console.log(ee)
}
let tabIndex = 2
const editableTabsValue = ref(store.zx.length)
const ff = store.zx;
const gg = (e) => {
  ff.forEach(item => {
    if (item.path == e) {
      ff.splice(item,1)
    }
  })
}
</script>

<style scoped>
.demo-tabs > .el-tabs__content {
  padding: 32px;
  color: #6b778c;
  font-size: 32px;
  font-weight: 600;
}
</style>

pinia里面的代码

import { defineStore } from 'pinia';

export default defineStore('auth',  {
   state: () => {
       return {
           loginName: "张三",
           ss: [],
           mm: [
               {
                 path: 'vv',
                 name:'首页',
                 func_fid: 0,
                 id:"1000",
                 children: [
                     {
                         path: 'sy',
                         name:'首页儿子',
                         func_fid: 1000,
                         id:"1212",
                     }
                 ]
               },
               {
                   path:'hh',
                   name:'系统管理',
                   func_fid: 0,
                   id: '1',
                   children: [
                       {
                           id: '1',
                           func_fid: 1,
                           path:'son1',
                           name: '系统管理儿子',
                       },
                       {
                           id:' 2',
                           func_fid: 1,
                           path:'hhh',
                           name: '系统管理-角色',
                           children: [
                               {
                                   id: '222',
                                   func_fid: 1,
                                   path: 'son1-1-1',
                                   name: '角色管理',
                                   children:[
                                       {
                                           id: '12',
                                           func_fid: 2,
                                           path: 'son1-1-1',
                                           name: '角色管理儿子',
                                           children:[
                                               {
                                                   id:' 122',
                                                   func_fid: 2,
                                                   path: 'son1-1-1',
                                                   name: '角色管理儿子-----孙子',
                                               }
                                           ]
                                       }
                                   ]
                               }
                           ]
                       },
                       {
                           id: '12',
                           path: 'son1-2',
                           name: '用户管理'
                       }

                   ]
               },
               {
                   path:'ss',
                   name:'教学管理',
                   id: '22',
                   func_fid: 0,
                   children: [
                       {
                           path:'son2',
                           name:'教学管理儿子',
                           id: '202',
                           func_fid: 22,
                       }
                   ]
               },
               {
                   path:'zz',
                   name:'行政管理',
                   id: '3',
                   func_fid: 0,
                   children: [
                       {
                           path:'son3',
                           name:'行政管理儿子',
                           id: '33',
                           func_fid: 3,
                       }
                   ]
               },

           ],
           zx:[],
           bbx:[],
           bbc: '',
       }
   },
    persist: {
        enabled: true, // 开启缓存  默认会存储在本地localstorage
        storage: sessionStorage, // 缓存使用方式
        paths:[] // 需要缓存键
    },
    actions: {
       zz(ss:string) {
           this.loginName = ss
       },
       vv(e) {
           let hh = [];
           function traverse(node) {
               hh.push(JSON.parse(JSON.stringify(node)))
               if (node.children && node.children.length > 0) {
                   for (let i = 0; i < node.children.length; i++) {
                       traverse(node.children[i]);
                   }
               }
           }
           this.mm.forEach(item => {
               traverse(item)
           })
           const bb =[]
           hh.forEach(item => {
              if (item.path == e) {
                  const index = this.zx.findIndex(i => JSON.stringify(i) === JSON.stringify(item));
                  this.bbc = item.path;
                  if (index === -1) {
                      this.zx.push({...item})
                  }
              }
           })
       },
        kk(e) {
            let i = this.zx.findIndex(item => item.path === e);
            if(e != this.bbc) {} //删除的是一个不激活的tab那么就什么都不做
            else if (this.zx.length === 1) //删除的是最后剩下的一个激活的tab
                this.bbc = '';
            else if (i === this.zx.length - 1) //删除的是最末尾的一个tab,让前面那个激活
                this.bbc = this.zx[i - 1].path;
            else                                 //删除的是中间的一个激活的tab
                this.bbc = this.zx[i + 1].path;

            this.zx.splice(i, 1);
        },
    }
})

安装

yarn add pinia-plugin-persistedstate
or
npm i  pinia-plugin-persistedstate

使用插件 在main.ts中注册

import { createApp } from "vue";
import App from "./App.vue";
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
createApp(App).use(pinia);

路由代码

// import {createRouter, createWebHistory, createWebHashHistory} from "vue-router";

// // 1. 配置路由
// const routes: ({ redirect: string; path: string } | { path: string; component: () => Promise<any> } | { path: string; component: () => Promise<any>; children: ({ path: string; components: { son2: () => Promise<any> } } | { path: string; components: { son3: () => Promise<any> } })[] } | { path: string; components: { son1: () => Promise<any> }; name: string; props: { son1: boolean } })[] = [
//     {path: '/', redirect: '/login'},
//     {path: '/login', component: () => import('../views/login.vue')},
//     {
//         path: '/home',
//         component: () => import('../views/home/home.vue'),
//         children: [
//             // {path: 'son1', name: 'son1', components: {son1: () => import('../views/home/son/son1.vue')}},
//             {path: 'son2', components: {son2: () => import('../views/home/son/son2.vue')}},
//             {path: 'son3', components: {son3: () => import('../views/home/son/son3.vue')}},
//         ]
//     },
//     {
//         path: '/son1',
//         name: 'son1',
//         components: {son1: () => import('../views/home/son/son1.vue')},
//         props: { son1: true }
//     }
//
// ];
// // 2.返回一个 router 实列,为函数,配置 history 模式
// const router = createRouter({
//     history: createWebHashHistory(),
//     routes,
// });
//
//
// // 3.导出路由   去 main.ts 注册 router.ts
//
// export default router

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
    history: createWebHistory(),
    routes: [
            {path: '/', redirect: '/login'},
    {path: '/login', component: () => import('../views/login.vue')},
    {
        path: '/home',
        component: () => import('../views/home/home.vue'),
        children: [
            {
                path:'',
                components: {
                    son1: () => import('../views/home/son/son1.vue'),
                    son2: () => import('../views/home/son/son2.vue'),
                    son3: () => import('../views/home/son/son3.vue'),
                    sy:() => import('../views/home/son/sy.vue'),
                }
            },
        ]
    },
    ]
})

export default router

我把代码放git上了,有需要的自行拉取

https://gitee.com/Flechazo7/vue3.git

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[进阶]Java:多线程:线程同步

线程同步 解决线程安全问题的方案。 线程同步的思想 让多个线程实现先后一次访问共享资源&#xff0c;这样就解决了安全问题。 线程同步的常见方案&#xff1a; 加锁&#xff1a;每次只允许一个线程加锁&#xff0c;加锁后才能进入访问&#xff0c;访问完毕后自动解锁&…

css 使用杂记

水平居中 条件&#xff1a;必须有宽度&#xff0c;不能无限宽 行内元素&#xff1a;通过设置父元素text-align:center块元素&#xff1a;要设置宽度&#xff0c;然后 左右margin值为“auto” 垂直居中 条件&#xff1a;父元素必须有高度&#xff0c;不能无限高 行内元素&#…

【Solr】体验极速安装solr

目录 前言 安装下载- 方式一&#xff1a;官网下载- 方式二&#xff1a;仓库下载 启动方式 快速使用 前言 solr是基于java开发的&#xff0c;所以solr需要用到jdk环境,并且solr需要在tomcat容器中才能运行,所以需要提前配置好jdk和tomcat环境。 安装下载 需要注意的是&#…

【vue+el-transfer】穿梭框实现及遇到的bug,已解决

昨晚加班写的穿梭框组件&#xff0c;一边写一边遇到bug&#xff0c;果然只有bug才会让你印象更深刻&#xff0c;更值得记录 封装成组件FreezeTransfer 效果如下&#xff1a; 主要参考了官网上可搜索的这个示例 先说遇到的bug&#xff0c;然后贴完整的代码 1、el-transfer数据…

layui下select下拉框不显示或没有效果

layui下select下拉框不显示或没有效果 弹层layer选择框没有样式_不可点击_渲染失效的解决办法 一、必须给表单体系所在的父元素加上 class"layui-form" 在一个容器中设定 class"layui-form" 来标识一个表单元素块&#xff0c;如果你不想用 form&#xf…

java 高校学生信息管理系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 JSP 高校学生信息管理系统 是一套完善的系统源码&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;以及相应配套的设计文档&#xff0c;系统主要采用B/S模式开发 。 研究的基本内容是基于Web的学生信息…

2023 最新版网络安全保姆级指南,手把手带你从零基础进阶渗透攻防工程师

一份网络攻防渗透测试的学习路线&#xff0c;不藏私了&#xff01; 2023最新500G《黑客&网络安全入门&进阶学习资源包》 1、学习编程语言(phpmysqljshtml) 原因&#xff1a;phpmysql 可以帮助你快速的理解 B/S 架构是怎样运行的&#xff0c;只有理解了他的运行原理才…

《机器学习公式推导与代码实现》chapter12-XGBoost

《机器学习公式推导与代码实现》学习笔记&#xff0c;记录一下自己的学习过程&#xff0c;详细的内容请大家购买作者的书籍查阅。 XGBoost 从算法精度、速度和泛化能力等性能指标来看GBDT&#xff0c;仍然有较大的优化空间。XGBoost是一种基于GBDT的顶级梯度提升模型。相较于…

提炼关键词是一种能力

提炼关键词&#xff0c;是一种能力 交流或写文字&#xff0c;都要提炼关键词 趣讲大白话&#xff1a;抓重点 【趣讲信息科技202期】 **************************** 大脑的信息通过关键词调取 语言的传达&#xff0c;通过关键词传递关键信息 搜索要输入关键词 人工智能也要提示关…

tensorRT 模型部署

讲解&#xff1a; 模型经过训练之后终端部署之前都会有一个模型转换的过程&#xff0c;英伟达也不例外&#xff0c; 模型转换的过程其实是一个模型优化与加速的过程&#xff0c;里面包含着引擎对模型的一系列操作&#xff0c; 比如说layer 级的融合&#xff0c;权重的量化、图层…

PMP考试中多少分算通过?

PMP考试成绩一般是在考完后 6-8 周开始出成绩&#xff0c;像之前318的PMP考试&#xff0c;5月8号晚上已经开始出成绩了&#xff0c;还没出来的也会陆续出来。 【如何查询成绩】 1、输入网址&#xff08;PMI官网&#xff0c;不知道网址的私戳&#xff09;&#xff0c;点击 Log …

消息中间件中常见问题

如何保证消息不丢失 MQ的用途 异步发送&#xff08;验证码&#xff0c;短信&#xff0c;邮件&#xff09;MySQL&#xff0c;ES&#xff0c;Redis之间的数据同步分布式事务削峰填谷 消息可能丢失的环境 消息在产生端时候生产端挂掉&#xff0c;消息未到达交换机&#xff0c…

【新车评分】降价三万,排名第一的蔚来ES7更能打了?

去年6月&#xff0c;蔚来上市了该品牌第四款SUV车型——ES7&#xff0c;共分为两个版本标准版和首发版&#xff0c;发售价分别为46.8万和54.8万元。 不过近期蔚来以砍掉部分车主权益&#xff0c;换来了全系车型3万元的降价&#xff0c;ES7的起售价也来到了43.8万元和51.8万元。…

【Python 随练】利用递归方法求 5!

题目 利用递归方法求 5!。 简介 在本篇博客中&#xff0c;我们将使用递归方法解决一个数学问题&#xff1a;计算一个数的阶乘。阶乘是指将从1到某个正整数n的所有整数相乘&#xff0c;通常表示为n!。我们将介绍递归的概念&#xff0c;并给出一个完整的代码示例来计算给定数的…

P-Tuning v2: 与微调性能相等的提示性优化

原文&#xff1a;P-Tuning v2: Prompt Tuning Can Be Comparable to Fine-tuning Universally Across Scales and Tasks 作者: Xiao Liu1,2 , Kaixuan Ji1 代码: https://github.com/THUDM/P-tuning-v2 一、简介 二、准备工作 ---- 2.1 NLU的任务 ---- 2.2 提示优化 三、P-Tu…

什么是云原生?

目录 1.简介2.云元素的四要素 1.简介 云原生&#xff1a;是一种构建和运行应用程序的方法&#xff0c;是一套技术体系和方法论。云原生&#xff08;CloudNative&#xff09;是一个组合词&#xff0c;Cloud Native&#xff1a; Cloud 表示应用程序位于云中&#xff0c;而不是…

基于OpenMV 循迹小车 + WIFI无线图传

文章目录 一、工程环境二、OpenMV1. 色块选定2. 色块识别3. 串口通信4. WiFi无线图传5. 代码汇总 三、MSP430四、视频演示 一、工程环境 1. 软件 OpenMV IDECode Composer StudioMicrosoft Edge 2. 硬件 MSP430F5529OpenMV4 H7及其 WiFi拓展板视觉云台旋转编码器、oled显示…

国际原油期货怎么开户?国际原油期货开户流程是什么?

随着国际原油期货交易的大众化&#xff0c;国际原油期货交易的入市门槛也在逐渐降低&#xff0c;使越来越多的国际原油期货交易爱好者能够参与到这个交易市场中。很多朋友可能对国际原油期货开户有很多的疑问&#xff0c;是不是很繁琐&#xff1f;需不需要很多的证明文件&#…

论文解读 | 皮质电图系统与软机器人致动器的完美结合

原创 | 文 BFT机器人 01 研究内容 主要研究内容是关于一种电皮层图谱系统的部署&#xff0c;该系统使用软体机器人致动器。论文详细介绍了该系统的制造和实验方法&#xff0c;并提供了相关的图表和参考文献。该系统的设计旨在提高电皮层图谱系统的灵活性和可植入性&#xff0c…

vite+vue3+cesium环境搭建

1.创建一个Vite项目 npm create vitelatest 2.安装cesium插件&#xff1a;vite-plugin-cesium npm i cesium vite-plugin-cesium vite -D 3、配置vite.config.js import cesium from vite-plugin-cesium; export default defineConfig({ plugins: [vue(),cesium()] }) 4、清空…