vue使用element实现折叠面板

先看一下最后的效果

正常
image.png

折叠后
image.png

可以看页面可以分为三部分,左边的sidebar、上面的topbar、和内容appMain
来看一下我代码的结构


image.png

上代码
// sidebar.vue
<template>
    <div class="sidebar-container" :class="{'collapse-width': isCollapse}">
        <div class="logo" :class="{'collapse-logo': isCollapse}">
            LOGO
        </div>
        <el-menu
                :default-active="onRoutes"
                class="el-menu-vertical"
                background-color="#304156"
                text-color="#bfcbd9"
                active-text-color="#10B9D3"
                mode="vertical"
                :collapse="isCollapse"
                unique-opened
                router
        >
            <el-menu-item index="dashboard">
                <i class="el-icon-menu"></i>
                <span slot="title">控制面板</span>
            </el-menu-item>
            <el-menu-item index="link1">
                <i class="el-icon-menu"></i>
                <span slot="title">导航一</span>
            </el-menu-item>
            <el-menu-item index="link2">
                <i class="el-icon-document"></i>
                <span slot="title">导航二</span>
            </el-menu-item>

        </el-menu>
    </div>
</template>

<script>
    import { mapState } from "vuex";

    export default {
        computed: {
            onRoutes() {
                return this.$route.path.replace("/", "");
            },
            ...mapState({
                isCollapse: (state) => state.common.isCollapse
            })
        },
        methods: {}
    }
</script>

<style lang="scss" scoped>
.collapse-width {
    width: 64px !important;
}
.collapse-logo {
    font-size: 18px !important;
}

.sidebar-container {
    width: 180px;
    height: 100%;
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    transition: width 0.28s;
    z-index: 1001;
    overflow: hidden;
    .el-menu-vertical:not(.el-menu--collapse) {
        width: 180px;
    }
    .el-menu {
        border: none;
        height: 100%;
        width: 100% !important;
        overflow-y: auto;
    }
    .logo {
        width: 100%;
        height: 50px;
        line-height: 50px;
        font-size: 30px;
        text-align: center;
        background-color: rgb(48, 65, 86);
        color: #fff;
    }
}
</style>
// topbar.vue
<template>
    <div class="topbar-container">
        <div class="toggle-btn" @click="toggleSidebar">
            <i class="fa fa-navicon"></i>
        </div>
    </div>
</template>

<script>
    import { mapState, mapActions } from 'vuex'
    import BreadCrumd from './breadCrumd'

    export default {
        data() {
            return {
            }
        },
        components: {
            BreadCrumd
        },
        computed: {
            ...mapState({
                isCollapse: (state) => state.common.isCollapse
            })
        },
        methods: {
            ...mapActions(['toggleSidebar'])
        }
    }
</script>

<style lang="scss" scoped>
    .topbar-container {
        width: 100%;
        height: 50px;
        line-height: 50px;
        border-bottom: 1px solid #ccc;
        background-color: #fff;
        .toggle-btn {
            display: inline-block;
            padding: 0 20px;
        }
    }
</style>
// appMain.vue
<template>
    <div class="app-main-container">
        <transition name="fade-transform" mode="out-in">
            <router-view></router-view>
        </transition>
    </div>
</template>

<script>
    export default {}
</script>

<style lang="scss" scoped>
    .app-main-container {
        position: absolute;
        width: 100%;
        height: calc(100% - 70px);
        margin: 10px;
        padding: 20px;
        background-color: #fff;
    }
</style>
// Breadcrumb
<template>
  <el-breadcrumb class="app-breadcrumb" separator="/">
    <transition-group name="breadcrumb">
      <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
        <span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
      </el-breadcrumb-item>
    </transition-group>
  </el-breadcrumb>
</template>

<script>
import pathToRegexp from 'path-to-regexp'  // npm包,运行 npm install path-to-regexp --save 下载

export default {
  data() {
    return {
      levelList: null
    }
  },
  watch: {
    $route() {
      this.getBreadcrumb()
    }
  },
  created() {
    this.getBreadcrumb()
  },
  methods: {
    getBreadcrumb() {
      // only show routes with meta.title
      let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
      const first = matched[0]

      if (!this.isDashboard(first)) {
        matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched)
      }

      this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
    },
    isDashboard(route) {
      const name = route && route.name
      if (!name) {
        return false
      }
      return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
    },
    pathCompile(path) {
      // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
      const { params } = this.$route
      var toPath = pathToRegexp.compile(path)
      return toPath(params)
    },
    handleLink(item) {
      const { redirect, path } = item
      if (redirect) {
        this.$router.push(redirect)
        return
      }
      this.$router.push(this.pathCompile(path))
    }
  }
}
</script>

<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
  display: inline-block;
  font-size: 14px;
  line-height: 50px;
  margin-left: 8px;

  .no-redirect {
    color: #97a8be;
    cursor: text;
  }
}
</style>
// 组装三个组件的index.vue
<template>
    <div>
        <SideBar></SideBar>
        <div class="right-container" :class="{'collapse-ml': isCollapse}">
            <TopBar></TopBar>
            <AppMain></AppMain>
        </div>
    </div>
</template>

<script>
    import { mapState } from 'vuex'
    import SideBar from './sideBar'
    import TopBar from './TopBar/index'
    import AppMain from './appMain'

    export default {
        computed: {
            ...mapState({
                isCollapse: (state) => state.common.isCollapse
            })
        },
       components: {
           SideBar,
           TopBar,
           AppMain
       }
    }
</script>

<style lang="scss" scoped>
.right-container{
    width: 100%;
    min-height: 100%;
    margin-left: 180px;
    transition: margin-left 0.28s;
}
.collapse-ml{
    margin-left: 64px
}
</style>
// vuex common.js
const common = {
    state: {
        isCollapse: false
    },
    mutations: {
        // 折叠侧边栏
        TOGGLE_SIDEBAR(state) {
            state.isCollapse = !state.isCollapse
        }
    },
    actions: {
        toggleSidebar({ commit }) {
            commit('TOGGLE_SIDEBAR')
        }
    }
}

export default common

码云地址
https://gitee.com/daijun1/vue-project-template

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 本文基于工作项目开发,做的整理笔记因工作需要,项目框架由最初的Java/jsp模式,逐渐转移成node/expre...
    SeasonDe阅读 7,548评论 3 35
  • 前端开发面试题 面试题目: 根据你的等级和职位的变化,入门级到专家级,广度和深度都会有所增加。 题目类型: 理论知...
    怡宝丶阅读 2,697评论 0 7
  • 谁也没有想到,来敲门的是安妮! 以前安妮在邵家圆木家生店隔壁的咖啡馆做服务生的时候,有空的时候常来串...
    楠溪陈酿阅读 384评论 2 0
  • 当羊哥说出:“老婆,我今天穿啥?”这句话时,我便再也无法忍受心中的怒火,像是胸中藏着三十只狮子猛然冲出栅栏,自己也...
    闲茶淡花阅读 440评论 2 2
  • 我喜欢晨跑,喜欢那清新的空气,喜欢那熟悉的跑道,喜欢那晨练的人们。感谢悦跑,带我走进跑步的行列;感谢跑步,带给你我...
    龙哥_5d6a阅读 452评论 0 0

友情链接更多精彩内容