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: {},
});
store/index.js

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>
views/layout.vue

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>
components\layoutAside.vue

 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>
components\layoutHeader.vue

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>
components\layoutTab.vue

 

posted @ 2022-05-13 17:32  生之韵  阅读(509)  评论(0)    收藏  举报