效果图
我这里是使用的vue2 + element-ui来实现的,代码可以直接拿来使用
一、首先先安装element-ui
npm i element-ui -S
然后在main.js里面配置,安装官网的步骤来就可以了,这里就不一一介绍了
import Vue from 'vue'; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import App from './App.vue'; Vue.use(ElementUI); new Vue({ el: '#app', render: h => h(App) });
二、vue页面
home页面
这个页面也就是主页,这里我把左侧菜单,中间内容的头部tab标签页给拆成了两个子组件他们分别是leftMenu.vue和multipleTabs.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>© 版权所有: 大可</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>
左侧菜单页面leftMenu.vue
<template> <div> <fragment v-for="(item, index) in list" :key="index"> <!-- 非叶子节点 --> <el-submenu v-if="item.children" :index="item.path"> <template slot="title"> <i class="el-icon-location"></i> <span class="menu" slot="title">{{ item.name }}</span> </template> <left-menu :dataToSon="item.children"></left-menu> </el-submenu> <!-- 叶子节点(功能节点) --> <el-menu-item v-else :index="item.path"> <i class="el-icon-menu"></i> <span class="menu" slot="title">{{ item.name }}</span> </el-menu-item> </fragment> </div> </template> <script> import leftMenu from '../../../src/views/home/leftMenu.vue' export default { // eslint-disable-next-line vue/multi-word-component-names name: 'leftMenu', components: { leftMenu }, props: ['dataToSon'], data () { return { isCollapse: false, list: [] } }, mounted () { this.list = this.dataToSon }, methods: { handleOpen (key, keyPath) { console.log(key, keyPath) }, handleClose (key, keyPath) { console.log(key, keyPath) } } } </script> <style scoped> </style>
头部tab标签页multipleTabs.vue
<template> <div> <el-tabs v-model="activeTab" type="card" closable > <el-tab-pane v-for="item in this.$store.state.tabOne" :key="item.id" :label="item.name" :name="item.path" > {{item.content}} </el-tab-pane> </el-tabs> </div> </template> <script> import { mapState, mapMutations } from 'vuex' export default { name: 'MultipleTabs', computed: { ...mapState({ vuexActiveTab: 'title' }), activeTab: { get () { return this.vuexActiveTab }, set (newValue) { this.handleTabChange(newValue) } } }, data () { return { editableTabsValue: this.$store.state.title } }, mounted () { console.log(this.$store.state.title) }, methods: { ...mapMutations(['SET_ACTIVE_TAB']), handleTabChange (tab) { this.SET_ACTIVE_TAB(tab) } } } </script> <style scoped> </style>
最后就是vuex里面的代码了
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { tree: [ { 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-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-1', name: '角色管理儿子-----孙子' } ] } ] } ] }, { id: '122', 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 } ] }, { path: 'cv', name: '测试管理', id: '4', func_fid: 0, children: [] } ], tabs: [], tabOne: [], title: 'vv' }, getters: { }, mutations: { tab (state, payload) { function recursion (t) { state.tabs.push(t) if (t.children && t.children.length > 0) { for (let i = 0; i < t.children.length; i++) { recursion(t.children[i]) } } } state.tree.forEach(item => { recursion(item) }) state.tabs.forEach(item => { if (item.path === payload) { const ind = state.tabOne.findIndex(i => i === item) state.title = item.path if (ind === -1) { state.tabOne.push(item) } } }) console.log(state.tabOne) }, SET_ACTIVE_TAB (state, newValue) { state.title = newValue } }, actions: { }, modules: { } })
到此左侧菜单和头部tab标签联动就已经完成了