最终效果:

 第一步:根据ElementUi制作Layout布局和菜单栏

在components下新建vue,layout.vue

代码:

<template>
	<div class="mainheight">
		<el-container class="all-height">
			<!--顶栏容器-->
			<el-header class="header">
				<div class="navbar">
					<el-image style="height: 30px;width: 30px;" :src="url"></el-image>
					<span style="margin-left: 8px;">{{appname}}</span>
				</div>
			</el-header>

			<!--主要区域容器-->
			<el-container class="all-height">
				<!--侧边栏容器-->
				<el-aside class="aside" width="240px">
					<div class="all-height">
						<!--@select="handleSelect" 导航监听-->
						<el-menu :default-active="String(activeNav)" class="all-height" unique-opened router>

							<template v-for="(item,index) in $router.options.routes" v-if="!item.hidden">
								<!--顶级菜单-->
								<el-menu-item v-if="!item.leaf && !item.leafthree" :index="item.children[0].path">
									<i :class="item.children[0].meta.icon"></i>
									<span slot="title">{{item.children[0].meta.title}}</span>
								</el-menu-item>
								<!--二级菜单-->
								<el-submenu :index="index+''" v-if="item.leaf">
									<template slot="title">
										<i :class="item.meta.icon"></i>
										<span slot="title">{{item.meta.title}}</span>
									</template>
									<el-menu-item v-for="child in item.children" v-if="!item.hidden" :index="child.path"
										:key="child.path">
										<span slot="title">{{child.meta.title}}</span>
									</el-menu-item>
								</el-submenu>

							</template>

						</el-menu>
					</div>
				</el-aside>

				<!--mian容器-->
				<el-main style="padding: 0;">
					<router-view></router-view>
				</el-main>
			</el-container>

		</el-container>
	</div>
</template>


<script>
	import index from '@/components/home/index'
	import set from '../../../set.json'
	export default {
		data() {
			return {
				appname: set.name,
				url: "http://" + set.selsectip + ":" + set.port + "/public/logo.ico"
			}
		},
		methods: {

		},
		computed: {
			activeNav() { //当前激活的导航
				return this.$route.path
			}
		},
		created() {
			console.log(this.$router.options.routes)
		}

	};
</script>

<style>
	.mainheight {
		position: fixed;
		height: 100%;
		width: 100%;
	}

	.all-height {
		height: 100%;
	}

	.header {
		width: 100%;
		box-sizing: border-box;
		border-bottom: 1px solid #ebebeb;
		background-color: #fff;
	}

	.navbar {
		font-size: 14px;
		position: relative;
		height: 100%;
		/*padding: 0 20px;*/
		display: flex;
		justify-content: space-between;
		align-items: center;
	}

	.navbar el-image {
		height: 30px;
		width: 30px;
	}

	.aside {
		height: 100%;
		margin: 0px;
		padding: 0px;
	}
</style>

效果如下:

 同时输出看看路由内容方便修改

第二步:加入选项卡Tab

因为选项卡中v-model参数和导航栏default-active功能一致,所以可以实现连接。

最终代码:

<template>
	<div class="mainheight">
		<el-container class="all-height">
			<!--顶栏容器-->
			<el-header class="header">
				<div class="navbar">
					<el-image style="height: 30px;width: 30px;" :src="url"></el-image>
					<span style="margin-left: 8px;">{{appname}}</span>
				</div>
			</el-header>

			<!--主要区域容器-->
			<el-container class="all-height">
				<!--侧边栏容器-->
				<el-aside class="aside" width="240px">
					<div class="all-height">
						<!--@select="handleSelect" 导航监听-->
						<el-menu :default-active="String(activeNav)" class="all-height" unique-opened router>

							<template v-for="(item,index) in $router.options.routes" v-if="!item.hidden">
								<!--顶级菜单-->
								<el-menu-item v-if="!item.leaf && !item.leafthree" :index="item.children[0].path">
									<i :class="item.children[0].meta.icon"></i>
									<span slot="title">{{item.children[0].meta.title}}</span>
								</el-menu-item>
								<!--二级菜单-->
								<el-submenu :index="index+''" v-if="item.leaf">
									<template slot="title">
										<i :class="item.meta.icon"></i>
										<span slot="title">{{item.meta.title}}</span>
									</template>
									<el-menu-item v-for="child in item.children" v-if="!item.hidden" :index="child.path"
										:key="child.path">
										<span slot="title">{{child.meta.title}}</span>
									</el-menu-item>
								</el-submenu>

							</template>

						</el-menu>
					</div>
				</el-aside>

				<!--mian容器-->
				<el-main style="padding: 0;">
					<el-tabs v-model="TabsValue" type="border-card" @tab-remove="removeTab" @tab-click="tabClick">

						<el-tab-pane v-for="item in TabsList" :key="item.name" :label="item.title" :name="item.name"
							:closable="item.closable" :ref="item.ref">
							<span slot="label"><i :class="item.icon"></i> {{item.title}}</span>
							<component :is="item.content"></component>
						</el-tab-pane>
					</el-tabs>
				</el-main>
			</el-container>

		</el-container>
	</div>
</template>


<script>
	import index from '@/components/home/index'
	import set from '../../../set.json'
	export default {
		data() {
			return {
				appname: set.name,
				url: "http://" + set.selsectip + ":" + set.port + "/public/logo.ico",
				TabsValue: 'index',
				TabsList: [{
					path: "/index", //path控制导航当前高亮
					title: '首页', //标题
					name: 'index', //用于显示当前名称
					icon: "el-icon-s-platform", //首页图标
					closable: false, //可否关闭
					ref: "tabs",
					content: index //路由显示页面地址
				}],
				TabsIndex: 1
			}
		},
		watch: {
			'$route': function(to) { //监听路由的变化,动态生成tabs
				let flag = true //判断是否需要新增页面
				let tabs = this.TabsList;
				const path = to.path
				// console.log(Object.keys(to.meta.title))
				if (Object.keys(to.meta).length != 0) {
					//console.log(tabs.name)
					for (let i = 0; i < tabs.length; i++) {
						if (tabs[i].name == to.meta.name) {
							this.TabsValue = tabs[i].name //定位到已打开页面
							//console.log("标签的名字:" + tabs[i].name)
							//console.log("菜单的名字:" + to.meta.name)
							flag = false
							break
						}
					}
					//新增页面
					if (flag) {
						//获得路由元数据的name和组件名
						const thisName = to.meta.name
						const thisTitle = to.meta.title
						const thisComp = to.meta.comp
						//console.log(thisComp)
						let newActiveIndex = ++this.TabsIndex + ''
						//console.log(newActiveIndex)
						//console.log("新增页面名字:"+thisName)
						this.TabsList.push({
							path: to.path,
							title: thisTitle,
							name: thisName,
							closable: true,
							ref: 'tabs',
							content: thisComp
						})
						this.TabsValue = thisName
					}
				}
			}
		},
		methods: {
			removeTab(targetName) {
				let tabs = this.TabsList;
				let activeName = this.TabsValue;
				if (activeName === targetName) {
					tabs.forEach((tab, index) => {
						if (tab.name === targetName) {
							let nextTab = tabs[index + 1] || tabs[index - 1];
							if (nextTab) {
								activeName = nextTab.name;
								this.tabClick(nextTab)
							}
						}
					});
				}
				this.TabsIndex = --this.TabsIndex + ''
				this.TabsValue = activeName;
				this.TabsList = tabs.filter(tab => tab.name !== targetName);
			},
			tabClick(thisTab) {
				/*
				 * thisTab:当前选中的tabs的实例
				 * 通过当前选中tabs的实例获得当前实例的path 重新定位路由
				 * */

				let val = this.TabsList.filter(item => thisTab.name == item.name)
				//console.log(val)
				this.$router.push({
					path: val[0].path
				})
			},
		},
		computed: {
			setHeight() {
				return document.documentElement.clientHeight - 60
			},
			setMainHeight() {
				return document.documentElement.clientHeight - 131
			},
			activeNav() { //当前激活的导航
				return this.$route.path
			}
		},
		created() {
			console.log(this.$router.options.routes)
			this.$router.push({
				path: "/"
			})
		}

	};
</script>

<style>
	.mainheight {
		position: fixed;
		height: 100%;
		width: 100%;
	}

	.all-height {
		height: 100%;
	}

	.header {
		width: 100%;
		box-sizing: border-box;
		border-bottom: 1px solid #ebebeb;
		background-color: #fff;
	}

	.navbar {
		font-size: 14px;
		position: relative;
		height: 100%;
		/*padding: 0 20px;*/
		display: flex;
		justify-content: space-between;
		align-items: center;
	}

	.navbar el-image {
		height: 30px;
		width: 30px;
	}

	.aside {
		height: 100%;
		margin: 0px;
		padding: 0px;
	}

	.el-tabs__item {
		font-size: 16px;
	}
</style>

源码地址:https://download.csdn.net/download/Mib_vi/34452700

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐