Vue - vue-admin-template模板项目改造:增加TopHeader(顶栏)

GitHub Demo 地址

在线预览

更新:对应的vue3版的demo如下:

GitHub Demo 地址

在线预览

前言

demo中的项目已经添加了TagsView功能和权限控制
关于TagsView功能的添加可以看:Vue - vue-admin-template模板项目改造:增加TagsView功能

有时项目需要在顶部显示一个header,在顶栏中显示项目标题和用户信息,这时需要对模块项目进行改造
demo项目中在原有的基础上进行了扩展,即可以支持原有方式展示,又可以通过setting配置显示顶栏

效果图

tagsView

请添加图片描述

topHeader + 隐藏logo

请添加图片描述

topHeader+fixedHeader

请添加图片描述

topHeader+fixedHeader+tagsView

请添加图片描述

涉及文件

因为顶栏要显示标题和用户信息,顶栏下方要显示面包屑和tagsView,所以新增了topHeaderHamburger文件
原有代码改造涉及layoutsetting相关文件,主要是在src\layout\index.vue文件进行功能扩展

src\layout\components\index.js
src\layout\index.vue
src\store\modules\settings.js
src\settings.js

在这里插入图片描述

涉及代码

src\layout\components\index.js 新增

export { default as TopHeader } from './TopHeader/TopHeader.vue' // TopHeader
export { default as Hamburger } from './TopHeader/Hamburger.vue' // Hamburger

src\layout\index.vue 全部代码

<template>
  <div :class="classObj" class="app-wrapper">
    <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
    <!-- 不带顶栏 -->
    <div v-if="!hasTopHeader">
      <sidebar class="sidebar-container" />
      <div :class="{hasTagsView:needTagsView}" class="main-container">
        <div :class="{'fixed-header':fixedHeader}">
          <navbar />
          <tags-view v-if="needTagsView" />
        </div>
        <app-main />
      </div>
    </div>

    <!-- 带顶栏 -->
    <div v-if="hasTopHeader" :class="{hasTopHeader:hasTopHeader}">
      <sidebar class="sidebar-container" style="top:60px;" />
      <top-header />
      <div :class="{hasTagsView:needTagsView}" class="main-container">
        <div :class="{'fixed-top-header':fixedHeader}">
          <hamburger />
          <tags-view v-if="needTagsView" />
        </div>
        <app-main />
      </div>
    </div>

  </div>
</template>

<script>
import { Navbar, Sidebar, AppMain, TagsView } from './components'
import { TopHeader, Hamburger } from './components'
import ResizeMixin from './mixin/ResizeHandler'

export default {
  name: 'Layout',
  components: {
    Navbar,
    Sidebar,
    AppMain,
    TagsView, // 新增tagsView
    TopHeader,
    Hamburger
  },
  mixins: [ResizeMixin],
  computed: {
    sidebar() {
      return this.$store.state.app.sidebar
    },
    device() {
      return this.$store.state.app.device
    },
    fixedHeader() {
      return this.$store.state.settings.fixedHeader
    },
    needTagsView() {
      return this.$store.state.settings.tagsView
    },
    hasTopHeader() {
      return this.$store.state.settings.topHeader
    },
    classObj() {
      return {
        hideSidebar: !this.sidebar.opened,
        openSidebar: this.sidebar.opened,
        withoutAnimation: this.sidebar.withoutAnimation,
        mobile: this.device === 'mobile'
      }
    }
  },
  methods: {
    handleClickOutside() {
      this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
    }
  }
}
</script>

<style lang="scss" scoped>
@import '~@/styles/mixin.scss';
@import '~@/styles/variables.scss';

.app-wrapper {
  @include clearfix;
  position: relative;
  height: 100%;
  width: 100%;
  &.mobile.openSidebar {
    position: fixed;
    top: 0;
  }
}
.drawer-bg {
  background: #000;
  opacity: 0.3;
  width: 100%;
  top: 0;
  height: 100%;
  position: absolute;
  z-index: 999;
}

.fixed-header {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 9;
  width: calc(100% - #{$sideBarWidth});
  transition: width 0.28s;
}

.hideSidebar .fixed-header {
  width: calc(100% - 54px);
}

.mobile .fixed-header {
  width: 100%;
}

/* TopHeader */
.hasTopHeader {
  padding-top: 60px;
  .fixed-top-header {
    position: fixed;
    top: 60;
    right: 0;
    z-index: 9;
    width: calc(100% - #{$sideBarWidth});
    transition: width 0.28s;
  }
  .fixed-top-header + .app-main {
    padding-top: 50px;
  }
  .hasTagsView {
    .fixed-top-header + .app-main {
      /* 84 = navbar + tags-view = 50 + 34 */
      padding-top: 84px;
    }
  }
}
.hideSidebar .fixed-top-header {
  width: calc(100% - 54px);
}
</style>

src\store\modules\settings.js 新增

const { showSettings, tagsView, fixedHeader, sidebarLogo, topHeader } = defaultSettings

const state = {
  showSettings: showSettings,
  tagsView: tagsView, // 新增tagsView
  fixedHeader: fixedHeader,
  sidebarLogo: sidebarLogo,
  topHeader: topHeader
}

src\settings.js 新增

  topHeader: true // topHeader显隐控制

topHeader文件

<template>
  <div class="top-header bgImage">
    <div class="header">
      <!-- 左侧标题 -->
      <div class="left">{{ headerTitle }}</div>
      <!-- 右侧 -->
      <div class="right">
        <!-- <div class="right-item">
          <img class="right-item-img" :src="avatar">
        </div> -->
        <!-- 用户信息 -->
        <el-dropdown trigger="click" placement="bottom">
          <div class="right-item">
            <img class="user-avatar" :src="avatar">
            <div class="user-name">{{ name }}</div>
            <i class="el-icon-caret-bottom" style="color:white;" />
          </div>
          <el-dropdown-menu slot="dropdown" class="user-dropdown">
            <router-link to="/">
              <el-dropdown-item> 首页 </el-dropdown-item>
            </router-link>
            <a target="_blank" href="https://github.com/iotjin/jh-vue-admin">
              <el-dropdown-item>Github</el-dropdown-item>
            </a>
            <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/zh/">
              <el-dropdown-item>Docs</el-dropdown-item>
            </a>
            <el-dropdown-item divided @click.native="logout">
              <span style="display:block;">退出登录</span>
            </el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
      </div>
    </div>
  </div>
</template>

<script>

import { mapGetters } from 'vuex'

export default {
  name: 'TopHeader',
  components: {
  },
  data() {
    return {
      // 顶栏标题
      headerTitle: 'Vue在线管理系统'
    }
  },
  computed: {
    ...mapGetters([
      'avatar',
      'name'
    ])
  },
  mounted() {
  },
  methods: {
    async logout() {
      await this.$store.dispatch('user/logout')
      this.$router.push(`/login?redirect=${this.$route.fullPath}`)
    }
  }
}
</script>

<style lang="scss" scoped>
.top-header {
  height: 60px !important;
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  z-index: 1001;
  font-size: 15px;
}
.bgImage {
  background: url('../../../assets/images/frame/header.png') no-repeat;
  background-size: 100% 100%;
}
.header {
  display: flex;
  align-items: center;
  height: 60px !important;
}
.left {
  flex: 3;
  padding-left: 30px;
  font-size: 20px;
  font-weight: bold;
  color: white;
}
.right {
  flex: 7;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  height: 60px !important;
  padding-right: 20px;
}
.right-item {
  display: flex;
  align-items: center;
  margin: 0px 10px;
  &:hover {
    background: rgba(0, 0, 0, 0.025);
  }
}
.right-item-img {
  cursor: pointer;
  width: 40px;
  height: 40px;
  border-radius: 10px;
}
.right-item-text {
  color: white;
  margin: 0px 5px;
}

.user-avatar {
  cursor: pointer;
  width: 40px;
  height: 40px;
  border-radius: 10px;
}
.user-name {
  color: white;
  margin: 0px 5px;
}
</style>

Hamburger文件

<template>
  <div class="navbar">
    <hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
    <breadcrumb class="breadcrumb-container" />
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import Hamburger from '@/components/Hamburger'

export default {
  components: {
    Breadcrumb,
    Hamburger
  },
  computed: {
    ...mapGetters([
      'sidebar'
    ])
  },
  methods: {
    toggleSideBar() {
      this.$store.dispatch('app/toggleSideBar')
    }
  }
}
</script>

<style lang="scss" scoped>
.navbar {
  height: 50px;
  overflow: hidden;
  position: relative;
  background: #fff;
  box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);

  .hamburger-container {
    line-height: 46px;
    height: 100%;
    float: left;
    cursor: pointer;
    transition: background 0.3s;
    -webkit-tap-highlight-color: transparent;

    &:hover {
      background: rgba(0, 0, 0, 0.025);
    }
  }

  .breadcrumb-container {
    float: left;
  }
}
</style>

至此结束

  • 6
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值