Skip to content
页面概要

布局

页面整体布局是一个产品最外层的框架结构,往往会包含导航、侧边栏、面包屑以及内容等。想要了解一个后台项目,先要了解它的基础布局。

本项目按照功能性简单的封装了以下几个布局,自己可以在此基础上改版。

位置

/src/layouts 目录下。

DefaultLayout

默认布局,如前台,游客可以直接访问的页面,可以使用此布局。

一、index.vue 布局内容如下:

vue
<script lang="ts" setup>
import { computed, ref } from "vue";
import { useRoute } from "vue-router";

import SwitchThemeModel from "@/components/SwitchThemeModel/index.vue";

import { formatRoutes } from "@/utils/router";
import { useTitle } from "@/composables/useTitle";
import layoutRotes from "./routes";

const route = useRoute();

// 框架所有菜单路由 与 patch key格式的所有菜单路由
const routerPathKeyRouter = ref(formatRoutes(layoutRotes));

// 当前路由 item
const routeItem = computed(() => routerPathKeyRouter.value.pathKeyRouter[route.path]);

// 设置title
useTitle(routeItem);
</script>
<template>
	<div class="default-layout">
		<div class="default-layout-header">
			<div class="default-layout-header-box">
				<div class="default-layout-logo">
					<img class="logo" src="../../assets/images/logo.png" />
					<span class="text">Frame-Template-Vue</span>
				</div>
				<div class="default-layout-nav">
					<router-link to="/" class="nav-item">首页</router-link>
					<router-link to="/member" class="nav-item">我的</router-link>
					<router-link to="/user/login" class="nav-item">登录</router-link>
					<router-link to="/test" class="nav-item">测试页</router-link>
					<span class="nav-item">
						<SwitchThemeModel />
					</span>
				</div>
			</div>
		</div>
		<router-view />
	</div>
</template>
<style scoped lang="scss">
.default-layout {
	position: relative;
	&::before {
		position: relative;
		display: block;
		width: 100%;
		height: 50px;
		content: "";
	}
	.default-layout-header {
		position: fixed;
		top: 0;
		right: 0;
		left: 0;
		z-index: 10;
		background-color: var(--ft-bg-color);
		border-bottom: 1px solid var(--ft-divider-color);
		.default-layout-header-box {
			position: relative;
			display: flex;
			align-items: center;
			max-width: 1200px;
			height: 50px;
			margin: 0 auto;
			.default-layout-logo {
				display: flex;
				align-items: center;
				width: 145px;
				padding-left: 5px;
				.logo {
					max-height: 20px;
					margin-right: 5px;
				}
				.text {
					font-size: 12px;
					font-weight: 500;
				}
			}
			.default-layout-nav {
				display: flex;
				flex: 1;
				align-items: center;
				justify-content: flex-end;
				.nav-item {
					padding: 0 8px;
					font-size: 12px;
				}
			}
		}
	}
}
</style>

布局内容只是样列,自己可以进行重构。

二、routes.ts 路由,内容如下:

ts
import { RouteRecordRaw } from "vue-router";

const DefaultLayoutRoutes: RouteRecordRaw[] = [
	{
		meta: {
			title: "首页",
		},
		path: "/",
		component: () => import("@/pages/home/index.vue"),
	},
	{
		path: "/test",
		component: () => import("@/pages/test/index.vue"),
	},
];

export default DefaultLayoutRoutes;

UserLayout

User布局,项目针对 登录页注册页 等,独立做了此布局,你也可以使用默认布局。

一、index.vue 布局内容如下:

vue
<script lang="ts" setup>
import { computed, ref } from "vue";
import { useRoute } from "vue-router";

import SwitchThemeModel from "@/components/SwitchThemeModel/index.vue";

import { formatRoutes } from "@/utils/router";
import { useTitle } from "@/composables/useTitle";
import layoutRotes from "./routes";

const route = useRoute();

// 框架所有菜单路由 与 patch key格式的所有菜单路由
const routerPathKeyRouter = ref(formatRoutes(layoutRotes));

// 当前路由 item
const routeItem = computed(() => routerPathKeyRouter.value.pathKeyRouter[route.path]);

// 设置title
useTitle(routeItem);
</script>
<template>
	<div class="user-layout">
		<div class="theme-switch"><SwitchThemeModel /></div>
		<router-view />
	</div>
</template>
<style scoped lang="scss">
.user-layout {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	height: 100vh;
	.theme-switch {
		position: fixed;
		top: 10px;
		right: 10px;
	}
}
</style>

布局内容只是样列,自己可以进行重构。

二、routes.ts 路由,内容如下:

ts
import { RouteRecordRaw } from "vue-router";

const UserLayoutRoutes: RouteRecordRaw[] = [
	{
		path: "/user",
		redirect: "/user/login",
		children: [
			{
				meta: {
					title: "登录",
				},
				path: "login",
				component: () => import("@/pages/user/login/index.vue"),
			},
		],
	},
];

export default UserLayoutRoutes;

SecurityLayout

认证布局,在实际应用中,我们不止需要像前台那样游客可以直接访问页面,还需要像后台那样登录认证后才能访问。

此布局是配合其他布局使用的。如:配合 MemberLayout

布局内容如下:

vue
<script lang="ts" setup>
import { onMounted } from "vue";
import { useRouter } from "vue-router";
import { useUserStore } from "@/store/user";
import PageLoading from "@/components/PageLoading/index.vue";

const router = useRouter();
const userStore = useUserStore();

// 读取当前用户信息
const getUser = async () => {
	const { code, msg } = await userStore.getInfo();
	if (code === 1) {
		// 未登录或登入信息失效
		router.replace({
			path: "/user/login",
			query: {
				redirect: router.currentRoute.value.path,
				...router.currentRoute.value.query,
			},
		});
	} else {
		if (code !== 0) {
			// 没有获取用户信息成功
			console.log("error msg", msg);
			alert(msg);
		}
	}
};
onMounted(() => {
	getUser();
});
</script>
<template>
	<router-view v-if="userStore.isLogin" />
	<PageLoading v-else />
</template>

MemberLayout

Member布局,在实际应用中,我们不止需要像前台那样游客可以直接访问页面,还需要像后台那样登录认证后才能访问,且需要验证权限等这样的功能。

一、index.vue 布局内容如下:

vue
<script lang="ts" setup>
import { computed, ref } from "vue";
import { useRoute } from "vue-router";

import Permission from "@/components/Permission/index.vue";
import SwitchThemeModel from "@/components/SwitchThemeModel/index.vue";

import { formatRoutes } from "@/utils/router";
import { useTitle } from "@/composables/useTitle";
import layoutRotes from "./routes";

const route = useRoute();

// 框架所有菜单路由 与 patch key格式的所有菜单路由
const routerPathKeyRouter = ref(formatRoutes(layoutRotes));

// 当前路由 item
const routeItem = computed(() => routerPathKeyRouter.value.pathKeyRouter[route.path]);

// 设置title
useTitle(routeItem);
</script>
<template>
	<div class="member-layout">
		<Permission :roles="routeItem?.meta?.roles">
			<router-view />
		</Permission>
		<div class="member-layout-footer">
			<div class="nav-item"><router-link to="/">首页</router-link></div>
			<div class="nav-item"><router-link to="/member/index">我的</router-link></div>
			<div class="nav-item"><router-link to="/user/login">登录</router-link></div>
			<div class="nav-item"><SwitchThemeModel /></div>
		</div>
	</div>
</template>
<style scoped lang="scss">
.member-layout {
	position: relative;
	&::after {
		position: relative;
		display: block;
		width: 100%;
		height: 40px;
		content: "";
	}
	.member-layout-footer {
		position: fixed;
		right: 0;
		bottom: 0;
		left: 0;
		z-index: 10;
		display: flex;
		height: 40px;
		background-color: var(--ft-bg-color);
		border-top: 1px solid var(--ft-divider-color);
		.nav-item {
			box-sizing: border-box;
			display: flex;
			flex: 1;
			align-items: center;
			justify-content: center;
			border-left: 1px solid var(--ft-divider-color);
			&:first-child {
				border: 0;
			}
		}
	}
}
</style>

二、routes.ts 路由,内容如下:

ts
import { RouteRecordRaw } from "vue-router";

const MemberLayoutRoutes: RouteRecordRaw[] = [
	{
		path: "/member",
		redirect: "/member/index",
		children: [
			{
				meta: {
					title: "用户中心",
				},
				path: "index",
				component: () => import("@/pages/member/index/index.vue"),
			},
			{
				path: "info",
				component: () => import("@/pages/member/info/index.vue"),
			},
		],
	},
];

export default MemberLayoutRoutes;

新增布局

你也可以新增扩展自己的布局,满足以下几个步骤:

  • 1、必须新建 .vue 文件,如: index.vue
  • 2、必须有路由定义文件,如:routes.ts
  • 3、最少新建以上两个文件,然后导入到 路由入口配置 /src/config/router.ts 文件中,可以参考以上几个布局样列。

Released under the MIT License.