14-Element-Plus实现后台管理系统布局

Vite2+Vue3+TypeScript+Element-plus脚手架搭建系列

✅01-初始化 Vite 项目
✅02-配置 Vite2 环境变量
✅03-Vite2 配置及说明
✅04-Vue3 使用 SCSS
✅05-Vue3 路由配置
✅06-TypeScript 配置及说明
✅07-Vue3 使用 axios
✅08-Vue3 axios 对象封装
✅09-ESLint 配置及说明
✅10-ESLint 与 Prettier 集成配置及说明
✅11-Mock.js 模拟接口数据
✅12-Vite2 引入 Element-Plus 框架
✅13-渐变+透明样式实现清爽登录页
✅14-Element-Plus 实现后台管理系统布局
✅15-Pinia 实现 store 状态管理
✅16-Vue3 动态路由权限控制


文章目录

  • Element-Plus实现后台管理系统布局
    • 目标
    • 准备
      • 安装依赖
      • 调整文件&目录
    • Coding
      • 添加查询用户信息 API
      • Mock 查询用户信息接口
      • 改造 Layout
      • Sidebar 组件
      • Header 组件
    • 结果

源码地址:GitHub / 码云


Element-Plus实现后台管理系统布局

目标

完成 Header、Sidebar、Footer 开发,mock 菜单和用户信息的接口数据。实现菜单收缩、展开、用户登出功能。

准备

安装依赖

npm install -S @element-plus/icons

调整文件&目录

src/components/layout 目录下创建 header、sidebar、footer 文件夹,用来布局用到的各子组件。
layout文件目录结构如下:
src

---- components

-------- layout

------------ footer

---------------- index.ts

------------ header

---------------- index.ts

------------ sidebar

---------------- index.ts

------------ index.ts

Coding

只粘贴了部分核心代码,完整代码可去 GitHub / 码云 获取

添加查询用户信息 API

src/api/login/index.ts 添加查询用户信息接口:

import http from '@/utils/http/index'

export default {
  // ↓登录
  signin: (data?: any) => {
    return http.post('/login/signin', data)
  },

  // ↓查询用户信息
  userInfo: () => {
    return http.get('/login/userInfo')
  },
}

Mock 查询用户信息接口

src/mock/login/index.ts mock 查询用户信息接口数据:

import Mock from 'mockjs'

// ↓mock数据
const data = Mock.mock({
  'info|1': [
    {
      baseInfo: {
        id: '@INCREMENT()',
        username: 'admin',
        name: '超级管理员',
        avatar: '@IMAGE(100, "#ffc72d", "Code-Bee"),',
      },
      menus: [
        {
          id: 1,
          name: '权限管理',
          icon: 'el-icon-menu',
          children: [
            { id: 2, name: '用户管理', path: '/sys/user' },
            { id: 3, name: '角色管理', path: '/sys/role' },
            { id: 4, name: '菜单管理', path: '/sys/menu' },
          ],
        },
        {
          id: 5,
          name: '系统管理',
          icon: 'el-icon-setting',
          children: [
            { id: 6, name: '系统字典', path: '/sys/dict' },
            { id: 7, name: '参数配置', path: '/sys/config' },
            { id: 8, name: '通知公告', path: '/sys/notice' },
            { id: 9, name: '日志审计', path: '/sys/log' },
          ],
        },
      ],
    },
  ],
})

export default [
  // ↓登录
  {
    url: new RegExp('/login/signin'),
    type: 'post',
    result: (config: any) => {
      const obj = JSON.parse(config.body)
      // ↓校验用户名密码
      if (obj.username !== 'admin' || obj.password !== '123456') {
        return {
          code: 400,
          data: null,
          message: '用户名或者密码错误',
        }
      }
      return {
        code: 200,
        data: data.info,
        message: '登录成功',
      }
    },
  },
  // ↓查询用户信息
  {
    url: new RegExp('/login/userInfo'),
    type: 'get',
    result: (config: any) => {
      return {
        code: 200,
        data: data.info,
        message: '登录成功',
      }
    },
  },
]

改造 Layout

修改 src/components/layout/index.vue ,引入封装好的其它子组件:

layout、sidebar、header 用到父子组件间的传值与修改

<template>
  <el-container>
    <Sidebar />
    <el-container>
      <el-header height="50px"><Header v-model:sidebar-collapse="sidebarCollapse" /></el-header>
      <el-main>
        <!-- ↓layout路由视图 -->
        <router-view></router-view>
      </el-main>
      <Footer />
    </el-container>
  </el-container>
</template>

<script>
import { defineComponent, ref, provide } from 'vue'
import Sidebar from './sidebar/index.vue'
import Header from './header/index.vue'
import Footer from './footer/index.vue'

export default defineComponent({
  name: 'Layout',
  components: { Sidebar, Header, Footer },

  setup() {
    // ↓侧边栏折叠
    const sidebarCollapse = ref(false)
    // ↓提供给sidebar注入
    provide('sidebarCollapse', sidebarCollapse)

    return {
      sidebarCollapse,
    }
  },
})
</script>

Sidebar 组件

src/components/layout/sidebar/index.vue 中编写菜单和 Logo ,数据 mock 获取:

<template>
  <div class="sidebar">
    <el-menu default-active="1-1" class="menu" :collapse="sidebarCollapse">
      <div class="logo">
        <img src="@/assets/logo-100.png" width="32" height="32" />
        <span v-show="!sidebarCollapse"> Code-Bee管理系统</span>
      </div>

      <el-sub-menu v-for="menu in userInfo.menus" :key="menu.id" :index="menu.id + ''">
        <template #title>
          <i :class="menu.icon"></i>
          <span>{{ menu.name }}</span>
        </template>
        <el-menu-item v-for="sub in menu.children" :key="sub.id" :index="sub.id + ''">{{ sub.name }}</el-menu-item>
      </el-sub-menu>
    </el-menu>
  </div>
</template>

<script lang="ts">
import { defineComponent, inject, onMounted, reactive, ref } from 'vue'
import loginApi from '@/api/login'

export default defineComponent({
  name: 'Sidebar',
  setup() {
    // ↓注入父组件值
    const sidebarCollapse = ref(inject('sidebarCollapse'))
    
    // TODO 用户信息变量,后续改成从store获取变量
    const userInfo = reactive({
      menus: [],
    })

    onMounted(() => {
      // ↓查询用户信息
      loginApi.userInfo().then((res: any) => {
        const { menus } = res.data
        userInfo.menus = menus
      })
    })

    return {
      sidebarCollapse,
      userInfo,
    }
  },
})
</script>

Header 组件

src/components/layout/header/index.vue 中编写侧边栏收缩开关及用户中心,数据 mock 获取:

<template>
  <div class="header">
    <div class="fold-icon" @click="toggle">
      <el-icon v-if="!sidebarCollapse" :size="24" color="#909399">
        <fold />
      </el-icon>
      <el-icon v-else :size="24" color="#909399">
        <expand />
      </el-icon>
    </div>

    <el-dropdown trigger="click">
      <div class="avatar">
        <el-avatar :src="userInfo.baseInfo.avatar"></el-avatar>
        <el-icon>
          <caret-bottom />
        </el-icon>
      </div>
      <template #dropdown>
        <el-dropdown-menu>
          <el-dropdown-item icon="el-icon-user">个人中心</el-dropdown-item>
          <el-dropdown-item icon="el-icon-right" divided @click="signout">退出用户</el-dropdown-item>
        </el-dropdown-menu>
      </template>
    </el-dropdown>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, reactive } from 'vue'
import { useRouter } from 'vue-router'
import loginApi from '@/api/login'

export default defineComponent({
  name: 'Header',

  props: {
    sidebarCollapse: {
      type: Boolean,
      default: false,
    },
  },

  emits: ['update:sidebarCollapse'],

  setup(props, { emit }) {
    const router = useRouter()

    // TODO 用户信息变量,后续改成从store获取变量
    const userInfo = reactive({
      baseInfo: {},
    })

    // ↓sidebar折叠/展开的开关
    const toggle = () => {
      // ↓修改父组件值
      emit('update:sidebarCollapse', !props.sidebarCollapse)
    }
    // ↓登出
    const signout = () => {
      // TODO 有store变量后需清除store变量
      router.push('/login')
    }

    onMounted(() => {
      // ↓查询用户信息
      loginApi.userInfo().then((res: any) => {
        const { baseInfo } = res.data
        userInfo.baseInfo = baseInfo
      })
    })

    return { userInfo, toggle, signout }
  },
})
</script>

结果

  • 菜单展开效果
    14-Element-Plus实现后台管理系统布局_第1张图片
  • 菜单收缩效果。
    14-Element-Plus实现后台管理系统布局_第2张图片
  • 点击用户登出返回到登录页面。

本文为博主原创文章,任何个人、团体、机构转载和摘录,请注明出处。

你可能感兴趣的:(vue,elementui,typescript,前端,前端框架)