vue2.0 - layout组件(五)SideBar和Main页面布局

本文详细介绍了Vue项目中如何使用El-Menu组件构建动态侧边栏,包括`index.vue`中的组件布局、`MenuItem`和`Link`组件的交互,以及如何结合Vuex管理路由状态。同时涵盖了Logo组件的折叠与Logo图片切换,以及`SidebarItem`的逻辑处理。
摘要由CSDN通过智能技术生成

1. SideBar下的组件
在这里插入图片描述
2. index.vue 页面内容

<template>
  <div class="asideNav">
    <!-- 如果不要Logo可以删除此代码 -->
    <Logo v-if="showLogo" :collapse="isCollapse"></Logo>
    <!--
        default-active:活动菜单颜色
        collapse:侧边栏隐藏
        background-color: 背景颜色
        text-color:菜单中文本颜色
        unique-opened: 是否唯一打开
        active-text-colo: 活动文本颜色
        collapse-transition: 隐藏过渡
        mode="vertical":绑定变量
       -->
    <el-menu
      :default-active="activeMenu"
      class="el-menu-vertical"
      :collapse="isCollapse"
      unique-opened
      active-text-color="#FFC000"
      background-color="#000000"
      text-color="skyblue"
      mode="vertical"
    >
     <sidebar-item 
      v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" />
    </el-menu>
  </div>
</template>
 
<script>
import { mapGetters } from 'vuex'
import Logo from './Logo'
import SidebarItem from './SidebarItem'
export default {
  data() {
    return {};
  },
  components: { SidebarItem, Logo },
  computed: {
   ...mapGetters([
      'sidebar'
    ]),
    routes() {
      return this.$router.options.routes;
    },
    activeMenu() {
      // 获取当前路由对象
      const route = this.$route;
      // 获取meta对象 和路径对象
      const { meta, path } = route;
      // 如果设置路径,侧栏将突出显示您设置的路径
      if (meta.activeMenu) {
        return meta.activeMenu;
      }
      return path;
    },
     // 显示logo
    showLogo() {
      return this.$store.state.settings.sidebarLogo;
    },
    // 是否关闭侧边栏
    isCollapse() {
      return !this.sidebar.opened
    }
  },
};
</script>
 
<style lang='scss' scoped>
.asideNav {
  text-align: left;
}
/*加快侧边栏文字消失的速度*/
.el-menu {
  transition: all 10ms;
}
</style>

3. Item.vue 页面内容

<script>
export default {
  name: 'MenuItem',
  functional: true,
  props: {
    icon: {
      type: String,
      default: ''
    },
    title: {
      type: String,
      default: ''
    }
  },
  render(h, context) {
    const { icon, title } = context.props
    const vnodes = []

    if (icon) {
      if (icon.includes('el-icon')) {
        vnodes.push(<i class={[icon, 'sub-el-icon']} />)
      } else {
        vnodes.push(<svg-icon icon-class={icon}/>)
      }
    }

    if (title) {
      vnodes.push(<span slot='title'>{(title)}</span>)
    }
    return vnodes
  }
}
</script>

<style scoped>
.sub-el-icon {
  color: currentColor;
  width: 1em;
  height: 1em;
}
</style>

4. Link.vue 页面内容

<template>
  <component :is="type" v-bind="linkProps(to)">
    <slot />
  </component>
</template>

<script>
import { isExternal } from '@/utils/validate'

export default {
  props: {
    to: {
      type: String,
      required: true
    }
  },
  computed: {
    isExternal() {
      return isExternal(this.to)
    },
    type() {
      if (this.isExternal) {
        return 'a'
      }
      return 'router-link'
    }
  },
  methods: {
    linkProps(to) {
      if (this.isExternal) {
        return {
          href: to,
          target: '_blank',
          rel: 'noopener'
        }
      }
      return {
        to: to
      }
    }
  }
}
</script>

5. Logo.vue 页面内容

<template>
  <div class="sidebar-logo-container" :class="{'collapse':collapse}">
    <transition name="sidebarLogoFade">
      <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
        <img v-if="logo" :src="logos" class="sidebar-logos">
      </router-link>
      <router-link v-else key="expand" class="sidebar-logo-link" to="/">
        <img v-if="logo" :src="logo" class="sidebar-logo">
      </router-link>
    </transition>
  </div>
</template>

<script>
export default {
  name: 'SidebarLogo',
  props: {
    collapse: {
      type: Boolean,
      required: true
    }
  },
  data() {
    return {
      title: '',
      logo: require('@/assets/logo.png'),
      logos: require('@/assets/do.png')
    }
  }
}
</script>

<style lang="scss" scoped>
.sidebarLogoFade-enter-active {
  transition: opacity 1.5s;
}

.sidebarLogoFade-enter,
.sidebarLogoFade-leave-to {
  opacity: 0;
}

.sidebar-logo-container {
  position: relative;
  width: 100%;
  height: 60px;
  line-height: 60px;
  background: #171717;
  text-align: center;
  overflow: hidden;

  & .sidebar-logo-link {
    height: 100%;
    width: 100%;

    & .sidebar-logo {
      vertical-align: middle;
      margin-right: 12px;
    }
      & .sidebar-logos {
      width: 32px;
      height: 32px;
      vertical-align: middle;
    }

    & .sidebar-title {
      display: inline-block;
      margin: 0;
      color: #fff;
      font-weight: 600;
      line-height: 50px;
      font-size: 14px;
      font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
      vertical-align: middle;
    }
  }

  &.collapse {
    .sidebar-logo {
      margin-right: 0px;
    }
  }
}
</style>

6. SidebarItem.vue 页面内容

<template>
  <div v-if="!item.hidden">
    <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
      <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
        <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
          <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
        </el-menu-item>
      </app-link>
    </template>

    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
      <template slot="title">
        <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
      </template>
      <sidebar-item
        v-for="child in item.children"
        :key="child.path"
        :is-nest="true"
        :item="child"
        :base-path="resolvePath(child.path)"
        class="nest-menu"
      />
    </el-submenu>
  </div>
</template>

<script>
import path from 'path' // 导入路径
import { isExternal } from '@/utils/validate' // 用于判断是外部的路径
import Item from './Item' // 迭代icon与title
import AppLink from './Link' // 应用关联 用于切换外部链接显示方法
// import FixiOSBug from './FixiOSBug' // 用于修复IOS设备鼠标离开bug

export default {
  name: 'SidebarItem',
  components: { Item, AppLink },
//   mixins: [FixiOSBug],
  props: {
    // route object 路由对象
    item: {
      type: Object,
      required: true
    },
    // 是否嵌套
    isNest: {
      type: Boolean,
      default: false
    },
    // 基本路径
    basePath: {
      type: String,
      default: ''
    }
  },
  data() {
    // To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
    // TODO: 渲染函数重构
    this.onlyOneChild = null
    return {}
  },
  methods: {
    // 有一个子路由
    hasOneShowingChild(children = [], parent) {
      const showingChildren = children.filter(item => {
        if (item.hidden) {
          return false
        } else {
          // 临时设置(如果只有一个子路显示子路由并使用)
          this.onlyOneChild = item
          return true
        }
      })

      // 当只有一个子路由器时,默认显示子路由器
      if (showingChildren.length === 1) {
        return true
      }

      // 如果没有要显示的子路由器,则显示父级
      if (showingChildren.length === 0) {
        this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
        return true
      }

      return false
    },
    // 解析路径
    resolvePath(routePath) {
      // 判断是否是外部的路径
      if (isExternal(routePath)) {
        return routePath
      }
      if (isExternal(this.basePath)) {
        return this.basePath
      }
      // 返回当前也解析好的路径
      return path.resolve(this.basePath, routePath)
    }
  }
}
</script>
<style lang="scss">
  .el-menu--collapse  .el-submenu__title span{
    display: none;
  }
  /*隐藏 > */
  .el-menu--collapse  .el-submenu__title .el-submenu__icon-arrow{
    display: none;
  }
</style>

Main.vue 页面内容(此二级路由不包含在Sidebar文件下)

<template>
  <section class="app-main">
    <transition name="fade-transform" mode="out-in">
      <router-view :key="key" />
    </transition>
  </section>
</template>

<script>
export default {
  name: 'AppMain',
  computed: {
    key() {
      return this.$route.path
    }
  }
}
</script>

<style scoped>
.app-main {
  /*50 = navbar  */
  height: 100%;
  width: 100%;
  position: relative;
  overflow: auto;
}
.fixed-header+.app-main {
  padding-top: 50px;
}
</style>

<style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {
  .fixed-header {
    padding-right: 15px;
  }
}
</style>

此时页面样式
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值