5、vue_Element Plus布局搭建页面基本结构
1、配置vuex
import { createStore } from "vuex";
export default createStore({
state: {
// 读取sessionStorage中的token,不存在默认空值
token: sessionStorage.getItem("token") || "",
// 定义侧边栏及menu初始状态:false
isCollapse: false,
// 定义tab页,
tabsList: [
{
name: "home",
label: "首页",
},
],
},
mutations: {
// 改变token
setToken(state, token) {
state.token = token;
// 存入sessionStorage
sessionStorage.setItem("token", token);
},
// 改变侧边栏及menu状态
changeSiderType(state) {
state.isCollapse = !state.isCollapse;
},
// 激活tab页
selectMenu(state, val) {
if (val.lable !== "home") {
let res = state.tabsList.findIndex((item) => item.name === val.name);
res == -1 ? state.tabsList.push(val) : "";
}
},
// 删除tab页
removeTab(state, val) {
let res = state.tabsList.findIndex((item) => item.name === val);
state.tabsList.splice(res, 1);
},
},
actions: {},
modules: {},
});
2、配置src/views/layout.vue
<template> <el-container> <el-aside :width="$store.state.isCollapse ? '64px' : '200px'"> <Aside /> </el-aside> <el-container> <el-header><Header /></el-header> <el-main> <Tab /> <router-view v-slot="{ Component }"> <keep-alive :include="$store.state.tabsList.map((item) => item.name)"> <component :is="Component" /> </keep-alive> </router-view> </el-main> </el-container> </el-container> </template> <script setup> import Header from "../components/layoutHeader.vue"; import Aside from "../components/layoutAside.vue"; import Tab from "../components/layoutTab.vue"; </script> <style lang="scss" scoped> .el-container { width: 100vw; height: 100vh; .el-aside { background: #134857; color: white; transition: all 0.5s; //aside过度效果时间设定 } .el-container { .el-header { height: 60px; background: #134857; color: white; display: flex; justify-content: space-between; } .el-main { padding: 6px; } } } </style>
3、配置components/layoutAside.vue
<template> <div class="logo"> <h3>{{ $store.state.isCollapse ? "Logo" : "石榴木工作室" }}</h3> </div> <el-menu :default-active="route.path" background-color="#134857" text-color="#ffffff" active-text-color="#ffd04b" :collapse="$store.state.isCollapse" :router="true" > <el-menu-item index="/"> <HomeFilled class="icons" /> <span>首页</span> </el-menu-item> <el-sub-menu :index="item.path" v-for="(item, index) in menusList" :key="index" > <template #title> <el-icon> <component class="icons" :is="item.icon"></component> </el-icon> <span>{{ item.label }}</span> </template> <el-menu-item :index="subItem.path" v-for="(subItem, subIndex) in item.childs" :key="subIndex" @click="clickMenu(subItem)" > <component class="icons" :is="subItem.icon"></component> <span>{{ subItem.label }}</span> </el-menu-item> </el-sub-menu> </el-menu> </template> <script setup> import { useRoute } from "vue-router"; import { useStore } from "vuex"; const route = useRoute(); const store = useStore(); // 获取菜单 const menusList = [ { name: "sale", path: "/sale", label: "销售管理", url: "sale", icon: "Menu", parent_name: "M", childs: [ { name: "salebill", path: "/salebill", label: "销售单管理", url: "/sale/salebill/index.vue", icon: "setting", parent_name: "sale", childs: [], }, ], }, { name: "system", path: "/system", label: "系统管理", url: "system", icon: "Menu", parent_name: "M", childs: [ { name: "user", path: "/user", label: "用户管理", url: "/system/user/index.vue", icon: "setting", parent_name: "system", childs: [], }, { name: "role", path: "/role", label: "角色管理", url: "/system/role/index.vue", icon: "setting", parent_name: "system", childs: [], }, ], }, ]; // 点击菜单 const clickMenu = (item) => { // console.log(item); store.commit("selectMenu", item); // 获取并存入当前菜单 let currentMenu = { name: item.name, label: item.label, }; sessionStorage.setItem("tabs", JSON.stringify(currentMenu)); }; </script> <style lang="scss" scoped> .logo { height: 60px; display: flex; justify-content: center; align-items: center; } .el-menu { border-right: none; } .icons { padding-right: 5px; height: 18px; width: 18px; } </style>
4、配置components/layoutHeader.vue
<template> <div class="header"> <div class="arrow"> <el-icon @click="handleCollapse"> <Fold v-if="!$store.state.isCollapse" /> <Expand v-else /> </el-icon> </div> <div class="menu"> <el-dropdown> <span class="el-dropdown-link"> <img class="user" :src="getImgSrc('user')" />{{ UserName }} </span> <template #dropdown> <el-dropdown-menu> <el-dropdown-item>个人中心</el-dropdown-item> <el-dropdown-item @click="loginout">退出</el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> </div> </div> </template> <script setup> import { ref } from "vue"; import { useRouter } from "vue-router"; import { useStore } from "vuex"; const router = useRouter(); const store = useStore(); const getImgSrc = (user) => { return new URL(`../assets/${user}.png`, import.meta.url).href; }; const handleCollapse = () => { // 调用mutations中的changeSiderType方法 store.commit("changeSiderType"); }; // 获取用户名 const UserName = ref(sessionStorage.getItem("UserName") || ""); // 退出 const loginout = () => { router.push("/login"); // store.dispatch("loginout"); }; </script> <style lang="scss" scoped> .header { width: 100%; display: flex; justify-content: space-between; /* 均匀排列每个元素 首个元素放置于起点,末尾元素放置于终点 */ align-items: center; /* 纵向居中 */ .arrow { display: flex; align-items: center; font-size: 20px; color: white; } .menu { display: flex; align-items: right; margin-right: 50px; span { display: flex; // 弹性布局 align-items: center; //垂直布局 color: white; font-size: 15px; } .user { width: 30px; height: 30px; border-radius: 50%; } } } </style>
5、配置components/layoutTab.vue
<template> <el-tabs v-model="activeName" type="card" :closable="tabsList.length > 1" class="demo-tabs tabs" @tab-click="handleClick" @tab-remove="removeTab" > <el-tab-pane class="tabs" v-for="(item, index) in tabsList" :key="index" :label="item.label" :name="item.name" > </el-tab-pane> </el-tabs> </template> <script setup> import { ref, reactive, watch, onMounted } from "vue"; import { useRouter, useRoute } from "vue-router"; import { useStore } from "vuex"; import { $msg } from "../utils/msg.js"; const route = useRoute(); const router = useRouter(); const store = useStore(); const activeName = ref(""); // 获取vuex中的tabList const tabsList = reactive(store.state.tabsList); // 点击tab页 const handleClick = (tab) => { // console.log(tab.props); router.push({ name: tab.props.name, }); let currentMenu = { name: tab.props.name, label: tab.props.label, }; // 当前tab页写入sessionStorage sessionStorage.setItem("tabs", JSON.stringify(currentMenu)); }; // 删除tab页 const removeTab = (tab, index) => { let length = tabsList.length - 1; if (tab === "home") { $msg("首页不能关闭"); return; } store.commit("removeTab", tab); if (tab !== route.name) { return; } router.push({ name: tabsList[length - 1].name, }); }; // 切换tab页的activeName watch( () => route.path, () => { activeName.value = route.name; }, { immediate: true } ); // 刷新时,将sessionStorage中的activeName添加到tabList onMounted(() => { let res = store.state.tabsList.findIndex((item) => item.name === route.name); res == -1 ? store.state.tabsList.push(JSON.parse(sessionStorage.getItem("tabs"))) : ""; }); </script>

浙公网安备 33010602011771号