最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • vue2.x从零到一的搭建自己风格的后台管理系统 - 项目整体布局

    正文概述 掘金(lirioing)   2020-12-01   515

    前言

    继续上篇的文章,本文继续进行搭建自己风格的后台管理系统,自定义页面布局和侧边栏,面包屑等页面基础功能。
    

    项目文件树

    上次文章只是提到了文件名,这次就把整个的文件树给结构放出来,及自己对文件夹的理解,顺便为以后的文章做做预告。
    

    vue2.x从零到一的搭建自己风格的后台管理系统 - 项目整体布局

    api

    这里是存放所有的请求接口,先分公共数据接口和普通数据接口,然后普通数据接口再进行模块划分。
    

    assets

    这里是配置一些公共的样式和图片,assets图片和static文件下的图片在HTML都是正常使用的,但是在js中使用的话,路径要经过webpack中的file-loader编译,
    路径不能直接写,需要用require引用。
    

    举个栗子

     <img :src="require('@/assets/img/loginImg.png')" />   
     data() {
        return {
            sysList: [
                {
                    id: 1,
                    logo: require("@/assets/img/stage/service.png"),
                    title: "系统",
                    hidden: true
                },
                {
                    id: 2,
                    logo: require("@/assets/img/stage/user.png"),
                    title: "中心",
                    hidden: true
                }
            ]
        }
     }
    

    components

    这里是放置公共组件的地方,写后台管理系统,一般elementUI的组件就基本上足够使用了,但是避免不了有些需求会写一些新组件,或者更多复用组件,减少CV
    大法。我对于这里的理解是,全局用的组件就直接以组件名为文件夹的命名写一个组件,模块组件就以模块名为文件夹的命名,在里面写组件。
    

    layout

    这里就是项目的整体布局的文件夹,如果有关页面的整体布局就是在这里修改。等下就回着重说一下这里的内容。
    

    router

    这里是vue的路由配置的地方。关于路由配置按照自己的项目实际情况进行调试。
    

    store

    这里是放全局数据的地方,使用的是vuex,状态管理模式。我的理解和组件那边类似,按照模块去给每一个modules命名,公共数据写在单独的modules中,getters
    引入所有的数据,同时对数据进行处理。
    

    utils

    这里是放置公共方法,request封装请求等的地方。
    

    views

    这里是写项目中每一个页面的地方,我对此的理解是,按模块划分不同的文件夹,不同模块下定义对应页面名称的文件夹,然后在里面添加2个文件, 对应的名称分别
    是index.vue,index.less,每个模块下的页面,重复性比较大的页面,可以共用一个页面,路由切换可以通过wacth去监听$route(to, from), 值得注意的地方
    是,刷新页面不会触发wacth监听的$route。
    

    App.vue

    这是根组件,就不过多介绍了,懂得都懂。
    

    main.js

    这里是项目的入口文件,所有页面都会加载这个文件,它的作用是实例化Vue,引入一些常用的公共功能和全局组件等。常用的公共功能有axios,vuex,router,权
    限控制等。
    

    permission.js

    这里是路由的钩子beforeEach,通过对权限的判断,来确定能不能跳转。我对此处的理解是,vuex状态管理模式,但是当页面刷新的时候,所有数据就会消失,所以
    需要在此处配置,以便刷新是继续获取到数据。
    

    theme

    这里是的在elementui官网,主题里面自定义的主题,后引用到项目中。
    

    .env系列

    这里是开发环境、测试环境和生产环境的配置。
    

    .gitlab-ci.yml

    这里是gitlab的CI工作流的配置,配置了一些语法指令。当代码上传到gitlab后,通过CI/CD调起dockerfile文件,去执行不同操作。
    

    dockerfile系列

    这里是dockerfile配置,通过gitlab的CI/CD工作流执行不同的dockerfile操作,最终实现自动化打包上测试环境/生产环境。
    

    babel.config.js

    这里是babel的配置
    

    vue.config.js

    这里是一个可选的vue配置文件,比如打包后的输出文件目录、放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录、devServer代理
    和disableHostCheck等。
    

    布局配置

    开始今天的正文,自定义项目的页面布局。
    

    页面文件布局和vue-element-admin保持高度一致,但是内容相对减少了许多,还是那句话,根据vue-element-admin修改成适用自己的框架。 vue2.x从零到一的搭建自己风格的后台管理系统 - 项目整体布局 这个是页面布局大致样子,可以根据自己的喜好去调整。简单介绍一下,左边aside是侧边栏,header中,左边是面包屑,右边是用户头像和一下拉选项卡等操作。main是项目页面的主要显示地方。 vue2.x从零到一的搭建自己风格的后台管理系统 - 项目整体布局

    layout index.vue

    <template>
        <div>
            <el-container>
                <el-aside width="210px" class="side">
                    <side-bar></side-bar>
                </el-aside>
                <el-container>
                    <el-header height="63px">
                        <nav-bar></nav-bar>
                    </el-header>
                    <el-main>
                        <keep-alive>
                            <router-view />
                        </keep-alive>
                    </el-main>
                </el-container>
            </el-container>
        </div>
    </template>
    <script>
    import NavBar from "./components/NavBar"
    import SideBar from "./components/Sidebar/index"
    export default {
        name: "layout",
        components: {
            "nav-bar": NavBar,
            "side-bar": SideBar
        }
    }
    </script>
    <style lang="less" scoped>
    // 清除el-header的padding:0 20px;的默认样式
    /deep/ .el-header{
        padding: 0;
    }
    
    /deep/ .el-main {
        background: #F0F4FA;
        overflow: auto;
        height: calc(100vh - 63px);
    }
    .side{
        min-height: 100vh;
        box-shadow: 2px 0px 8px 0 #d2dbe8;
        z-index: 1;
    }
    </style>
    

    layout-components-navbar.vue

    <template>
        <div mode="horizontal" class="headerBar">
            <div class="headerBar__loginSwitch">
                <img src="@/assets/img/switch.png"  @click="changeCollapse" />
                <el-breadcrumb separator-class="el-icon-arrow-right">
                    <el-breadcrumb-item to="/xxx">{{ navbar }}</el-breadcrumb-item>
                    <el-breadcrumb-item v-for="(item, index) in matchedRoute" :key="index" :to="item.path">	
                    {{item.name}}</el-breadcrumb-item>
                </el-breadcrumb>
            </div>
            <div class="headerBar__loginInfo">
                <img :src="require('@/assets/img/loginImg.png')" />
                <el-dropdown class="user" trigger="click" @command="handleCommand">
                    <span>
                        zhongshi<i class="el-icon-arrow-down el-icon--right"></i>
                    </span>
                    <el-dropdown-menu slot="dropdown">
                        <!-- <el-dropdown-item command="user">个人中心</el-dropdown-item> -->
                        <el-dropdown-item command="back">返回首页</el-dropdown-item>
                        <el-dropdown-item command="quit">退出登录</el-dropdown-item>
                    </el-dropdown-menu>
                </el-dropdown>
            </div>
        </div>
    </template>
    

    layout-components-sidebar-index.vue

    <template>
        <div class="navWrap">
            <div class="logo">
                <img src="@/assets/img/logo.png"  @click="toStage">
            </div>
            <el-scrollbar>
                <el-menu
                    :default-active="activeMenu"
                    :unique-opened="true"
                    :collapse-transition="false"
                    :collapse="false" 
                    mode="vertical"
                    router>
                    <sidebar-item v-for="route in routes" :key="route.path" :item="route" />
                </el-menu>
            </el-scrollbar>
        </div>
    </template>
    <script>
    import SidebarItem from './SidebarItem'
    import { mapGetters } from 'vuex'
    export default {
        components:{
            SidebarItem
        },
        computed: {
            ...mapGetters([
                "routes"
            ]),
            activeMenu() {
                const route = this.$route
                const { meta, path } = route
                return path
            },
            collapse() {
                return this.$store.state.settings.collapse
            }
        },
        methods: {
            toStage() {
                this.$router.replace('/stage')
            }
        }
    }
    </script>
    <style lang="less" scoped >
    .navWrap {
        height: 100%;
        background: #fff;
        box-shadow: 2px 0 8px 0 #D2DBE8;
    
        .logo {
            width: 200px;
            height: 63px;
            text-align: center;
            line-height: 63px;
    
            img{
                width: 171px;
                height: 27px;
                vertical-align: middle;
                cursor: pointer;
            }
        }
    
        .el-menu {
            height: 100%;
            border: none;
        }
        .el-menu-item.is-active {
            background-color: #f0f4fa;
            color: #3e4552;
            font-size: 14px;
            border-left: 3px solid #3d71ff;
        }
    }
    </style>
    

    layout-components-sidebar-sidebaritem.vue

    这里是展示侧边栏最主要的地方,我目前只做到了能够使用,但是对于完美使用还有一些距离,侧边栏小图片暂时还没加入进去,然后无限循环也没有加入进去,也就是vue-element-admin递归配置每一项我没有摸透,就没有采用。处于待优化状态

    <template>
        <div v-if="!item.hidden">
            <template v-if="hasOneShowingChildren(item.children)">
                <el-menu-item :index="item.path" :key="item.path">
                    <span slot="title">
                        {{ item.name }}</span>
                </el-menu-item>
            </template>
    
            <template v-else>
                <el-submenu :index="item.path + '/' + item.children[0].path" :key = "item.children[0].name">
                    <template slot="title">
                        <span slot="title">{{ item.name }}</span>
                    </template>
                    <template v-for="child in filterChildren(item.children)">
                        <el-submenu v-if="child.children && child.children.length > 0 && hasOneShowingChildren(child.children)"
                                    :index="item.path+'/'+child.path"
                                    :key="child.name">
                            <template slot="title">
                                <span>{{child.name}}</span>
                            </template>
                        </el-submenu>
                        <el-menu-item v-else
                                    :index="item.path+'/'+child.path"
                                    :key="child.name">
                            <span>{{ child.name }}</span>
                        </el-menu-item>
                    </template>
                </el-submenu>
            </template>
        </div>    
    </template>
    <script>
    import path from "path"
    export default {
        name: "SidebarItem",
        props: {
            item: {
                type: Object,
                required: true
            },
        },
        computed: {
            filterChildren() {
                return function(children) {
                    return children.filter(i => !i.hidden)
                }
            }
        },
        data() {
            this.onlyOneChild = null;
            return {}
        },
        methods: {
            hasOneShowingChildren(children = []) {
                const showingChildren = children.filter(item => {
                    return !item.hidden;
                });
                if (showingChildren.length === 1) return false
                return false;
            }
        }
    }
    </script>
    <style lang="less" scoped>
    .el-menu-item.is-active {
        background-color: #f0f4fa;
        color: #3d71ff;
        font-size: 14px;
        border-left: 3px solid #3d71ff;
    }
    </style>
    

    其他

    侧边栏都出来了,肯定是要配置路由了呀,我这边采用的是动态路由配置。
    

    router-index.js

    import Vue from "vue";
    import Router from "vue-router";
    // 第三方库需要use一下才能用
    Vue.use(Router)
    
    const originalPush = Router.prototype.push
       Router.prototype.push = function push(location) {
       return originalPush.call(this, location).catch(err => err)
    }
    export const defaultRoutes = [
        {
          path: "/",
          component: () => import("@/views/login"),
          hidden: true,
        },
        {
            path: "/login",
            name: "登录",
            component: () => import("@/views/login"),
            meta: { title: "登录", icon: "dashboard", affix: true },
            hidden: true,
        },
    
    ]
    
    const router = new Router({
        routes: defaultRoutes
    });
    
    export default router
    

    router-user.js

    export default [{
        path: "/user",
        component: "layout/index",
        redirect: "/user/set",
        hidden: false,
        name: "个人管理",
        children: [
            {
                path: "set",
                name: "个人设置",
                component: "views/user/set/index",
                meta: { title: "个人设置", icon: "dashboard", affix: true },
            }
        ]
    }]
    

    总结

    本文到这里就结束了,下一篇文章就是关于动态路由的配置和使用。相信就在不太久将来。


    起源地下载网 » vue2.x从零到一的搭建自己风格的后台管理系统 - 项目整体布局

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元