效果图
我这里是使用的vue2 + element-ui来实现的,代码可以直接拿来使用
一、首先先安装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标签联动就已经完成了